home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr48 / 386p_200.zip / 386POWER.ASM < prev    next >
Assembly Source File  |  1995-01-15  |  139KB  |  4,050 lines

  1. ; 386POWER is part of the public domain portion of the XGE system
  2. ; XGE == eXtended Game Engine toolkit
  3. ; See 386power.txt and history.txt for more info & credits
  4.  
  5.         .386p
  6.         
  7. ; respect this segment order or you'll get troubles
  8. NOSMART
  9. NOJUMPS
  10.  
  11. code16  segment para public use16
  12. code16  ends
  13. code32  segment para public use32
  14. code32  ends
  15. codeend segment page stack use32 'stack'
  16. codeend ends
  17.  
  18. ; Here follows the dos extender identifiers in "implementation order"
  19. IS_VCPI  = 0
  20. IS_DPMI  = 1
  21. IS_XMS   = 2
  22. IS_HARD  = 3
  23.  
  24. LOWMIN           =128      ; minimum free low memory (in K)
  25. EXTMIN           =512      ; minimum free extended memory (in K)
  26.  
  27. STACKSIZE        =0FFFh ; TOTAL AVAILABLE stack size in paragraphs
  28. STACKUSER        =0400h ; PROT. MODE MAIN STACK space in paragraphs
  29.  
  30. STACKSWTR        =0080h  ; STACK SIZE (in paragraphs ) available in real mode
  31.                          ; after a mode switch from prot. mode
  32. STACKSWTP        =0080h  ; STACK SIZE (in paragraphs) available in prot. mode
  33.                          ; after a mode switch from real mode
  34.  
  35. SWITCHSTACK    =0010h  ; STACK SIZE (in paragraphs) available in real mode
  36.                        ; for "int 31h" direct switches under DPMI
  37.                        ; and when reflecting irqs
  38. CR = 13
  39. LF = 10
  40.  
  41. ;=======================================
  42. ; Real mode and 16bit 386 code
  43. ;=======================================
  44.  
  45.  
  46. code16  segment para public use16
  47.         assume cs:code16, ds:code32, fs:code32
  48.         align byte
  49.                   
  50. typemsg:  ;writes a message to consolle
  51.         pushf
  52.         push ds
  53.         push es
  54.         push fs
  55.         push gs
  56.         pushad
  57.         mov ah,09
  58.         int 21h
  59.         popad
  60.         pop gs
  61.         pop fs
  62.         pop es
  63.         pop ds
  64.         popf
  65.         ret
  66.         
  67. ; this macro is used to produce debug messages while in V86 mode
  68. say macro t_item
  69.         push edx
  70.         mov edx,offset t_item
  71.         call typemsg
  72.         pop edx
  73.         endm        
  74.         
  75. ; d16ttty calls the dos function int 21h, ah=09
  76. ; under DPMI once the critical segments are set up 
  77.  
  78. d16tty:
  79.         ; DPMI teletyper
  80.  
  81.         pushad
  82.         pushfd
  83.         push ds
  84.         push es
  85.         push fs
  86.         push gs
  87.  
  88.         push ds
  89.         pop  es
  90.  
  91.         mov eax,switchstackaddr
  92.         mov V86ds,code32
  93.         mov V86edx,edx
  94.         mov V86ah,9
  95.         mov bx,0021h        ; call int 21h
  96.         mov tempstack,eax   ; set stack for direct DPMI calls
  97.         mov cx,0
  98.         mov edi, offset V86edi
  99.         mov ax,300h
  100.         int 31h
  101.         xor eax,eax       ; set back dpmi stack to default
  102.         mov tempstack,eax ; "use small DPMI stack" value
  103.  
  104.         pop gs
  105.         pop fs
  106.         pop es
  107.         pop ds
  108.         popfd
  109.         popad
  110.         ret
  111.         
  112. psay macro d_item
  113.         push edx
  114.         mov  edx, offset d_item
  115.         call d16tty
  116.         pop edx
  117.         endm
  118.  
  119. DOSRAMTOP = 0002
  120.         align byte ; we need byte align to "inline" the CPUID instruction
  121. Boot16: ; DOS EXTENDER starts here and kicks program into 386 protected mode
  122.  
  123.         mov ax,code32   ;
  124.         mov ds,ax       ; program data is into the 32bit segment
  125.  
  126.         cld ; DEFAULT INCREMENT DIRECTION IS UP!!!!!!
  127.         
  128.         mov ax,0003 ; set 80x25 text mode for text output
  129.         int 10h     ;
  130.         
  131.         ; show who holds the copyrights etc. etc.
  132.         mov dx,small offset _386power_info
  133.         mov ah,09
  134.         int 21h
  135.  
  136.         ;========================================================
  137.         ; Detect if current processor is a 386 or more
  138.         ; checking what happens to the flags when pushed on stack
  139.         ; or when special flags are flipped
  140.         ; CHECK CPU TYPE
  141.         ; (N.B. nothing is checked about Floating Point Unit capabilities!!!!)
  142.  
  143.         mov cx,0F000h  ; CL processor type 0 (8086) in case of exit
  144.                        ; CH = mask for flags
  145.  
  146.         pushf  ; copy FLAGS to BX
  147.         pop bx ;
  148.  
  149.         mov ax,bx  ; try to clear high 4 bits of FLAGS
  150.         and ah,0fh ;
  151.         push ax    ;
  152.         popf       ;
  153.         pushf      ;
  154.         pop ax     ; result into ax
  155.  
  156.         and ah,ch             ; check high 4 bits
  157.         cmp ah,ch             ;
  158.         je short ccheckdone ; if bits are set, CPU is 8086/8
  159.  
  160.         mov cl,2 ; 286 ?
  161.  
  162.         or bh,ch ; try to set high 4 bits of FLAGS
  163.         push bx  ;
  164.         popf     ;
  165.         pushf    ;
  166.         pop ax   ;
  167.  
  168.         and ah,ch           ; check high 4 bits
  169.         jz short ccheckdone ; if bits are not set, CPU is 80286
  170.  
  171.         inc cl  ; 386dx/sx
  172.  
  173.         pushfd   ; copy EFLAGS to EBX
  174.         pop ebx  ;
  175.  
  176.         mov eax,ebx     ; try to flip AC bit in EFLAGS
  177.         xor eax,40000h  ;
  178.         push eax        ;
  179.         popfd           ;
  180.         pushfd          ;
  181.         pop eax         ;
  182.         xor eax,ebx         ; AC bit fliped?
  183.         jz short sccheckdone; if no, CPU is 386
  184.  
  185.         inc cl ; 486dx/sx
  186.  
  187.         mov eax,ebx      ; try to flip ID bit in EFLAGS
  188.         xor eax,200000h  ;
  189.         push eax         ;
  190.         popfd            ;
  191.         pushfd           ;
  192.         pop eax          ;
  193.  
  194.         xor eax,ebx         ; ID bit fliped?
  195.         jz short sccheckdone; if no, CPU is an "old" 486
  196.         ; this is a Pentium or a "recent" Intel CPU with
  197.         ; CPUID support
  198.  
  199.         push ecx ;save counter
  200.         xor eax,eax ; eax=0 --> "check for CPUID and gimme vendor info"
  201.         nop ; a nop is a good thing to avoid undocumented bugs
  202.         db 0Fh,0A2h ; CPUID OPCODE
  203.         nop
  204.         pop ecx ; restore
  205.         cmp eax,1 ; if eax==1 then this is the "real" CPUID
  206.         jne short sccheckdone ; Bah! it was just a "not CPUID" thing
  207.         nop
  208.         ; eax = 1 , "hey CPUID! Gimme processor info"
  209.         db 0Fh,0A2h
  210.         nop
  211.         and ah,0Fh ; select "processor family" info
  212.         mov cl,ah ; set CL = "processor family" code
  213. sccheckdone:
  214.         push ebx  ; restore flags as found at start of test
  215.         popfd     ;
  216. ccheckdone:
  217.         mov _CPUPower,cl
  218.         cmp cl,3  ; at least a 386 ?
  219.         jnb Is386 ;
  220. NotA386: ; if some higher bits are zeroed this is a 286
  221.         xor ch,ch
  222.         mov bx, offset msg_cputype
  223.         add cx,cx
  224.         add cx,cx
  225.         add bx,cx
  226.         mov dx,[bx]
  227.         jmp exit16err
  228.  
  229. Is386:  ; this is a 386 or a 486 or a Pentium
  230.         and ecx,0FFh
  231.         mov edx,[ecx*4+msg_cputype]
  232.         call typemsg
  233.         ;=======================================================
  234.         ; now we can use all the features a 386 has
  235.  
  236.         cld    ; default direction is down
  237.         pushf         ; Set current V86 virtual Flag register
  238.         pop ax        ;
  239.         mov V86F,ax   ;
  240.  
  241.         ;==============================================================
  242.         ; save current interrupt table
  243.         say msg_gints
  244.         ; copy old ints to _OldInt table before kicking into prot. mode
  245.         mov si,offset _OldInt
  246.         mov ax,03500h ; get interrupt vectors
  247.         push es
  248. getints:
  249.         int 21h
  250.         mov [si],bx
  251.         mov [si+2],es
  252.         add si,4
  253.         inc al
  254.         jnz getints
  255.         pop es
  256.         
  257.         cli ; turn off interrupts, while initializing we don't want
  258.             ; other things around
  259.  
  260.         ;===========================================================
  261.         ; Now it's time to convert pointers from
  262.         ; seg:ofs to LINEAR and/or CODE32 OFFSETS
  263.  
  264.         xor eax,eax      ;
  265.         mov ax,es        ; PSP LINEAR OFFSET
  266.         shl eax,4        ;
  267.         mov _PSPBase,eax ;
  268.  
  269.  
  270.         mov eax,code16      ; CODE16 LINEAR OFFSET
  271.         shl eax,4           ;
  272.         mov _Code16Base,eax ;
  273.         or dword ptr baseGDTcode16,eax ; SET UP code16 GDT entry
  274.         or dword ptr baseGDTdata16,eax ; SET UP data16 GTD entry
  275.  
  276.         mov eax,code32      ; CODE32 LINEAR OFFSET
  277.         shl eax,4           ;
  278.         mov _Code32Base,eax ;
  279.         or dword ptr baseGDTcode32,eax ; SET UP code32
  280.         or dword ptr baseGDTdata32,eax ; and data32 GTD entries
  281.         
  282.         add dword ptr bases16_GDTaddr,eax ; SET UP GTD descriptor
  283.         
  284.         mov ebx,codeend            ; eax == code32  linear address
  285.         shl ebx,4                  ; ebx == codeend linear address
  286.         sub ebx,eax                ; ebx == codeend offset from code32
  287.         mov _LoMemBase,ebx         ; set _LoMemBase ( it grows up   )
  288.                                    ; at stack segment
  289.  
  290.         mov Stack32BaseOffset,ebx ; set Stack32BaseOffset
  291.                                   ; stack base position
  292.                                   ; as code32 relative offset
  293.  
  294.         xor edx,edx                 ;
  295.         mov dx,es:[DOSRAMTOP]       ; get low memory size in paragraphs
  296.         shl edx,4                   ; paragraphs to bytes
  297.         sub edx,eax                 ; code32 relative offset
  298.         mov _LoMemTop,edx           ; set _LoMemTop
  299.         sub edx,ebx ; get memory between _LoMemBase and _LoMemTop
  300.                     ; (stack size included)
  301.         mov dx,offset em1_no_lomem
  302.         cmp edx,(LOWMIN*1024)
  303.         jnb short ramright
  304.         jmp exit16err
  305. ramright:
  306.         
  307.         mov eax,((1+STACKSIZE)*16) ; set up stack frame with an extra paragraph
  308.         call InitAlloc             ; (initial _LoMemBase was at stack segment
  309.                                    ;  NOW will be after the stack)
  310.  
  311.         ; allocate mode switch private stack
  312.         mov eax,((1+SWITCHSTACK)*16)
  313.         call InitAlloc
  314.         add eax,15 ; round to paragraph
  315.         shr eax,4  ;
  316.         add eax,code32     ; get real mode segment address
  317.         shl eax,16                  ; get COMPLETE
  318.         mov ax,(SWITCHSTACK*16)   ; real mode FAR pointer
  319.         mov switchstackaddr,eax ; SS:SP of real mode stack to use when
  320.                            ; calling real mode from dpmi during "d16tty"
  321.  
  322.  
  323.         push es ; save PSP seg (DPMI test may kill ES)
  324.  
  325.         ; HERE the possible "dos-extender interface" hookers diverge
  326.  
  327.         say msg_DPMItest
  328.         ; now TEST FOR DPMI
  329.     mov ax,1687h   ; Get Real-to-Protected-Mode Switch entry point:
  330.                ;
  331.                ; The entry point you get must be called ONLY ONCE
  332.                ; FOR THE FIRST SWITCH to DPMI protected mode.
  333.                ; Input:
  334.                ;    AX = 1687h
  335.                ; Output:
  336.                ;    AX = 0 if function successfull
  337.                ;        BX = DPMI flags
  338.                        ;             bit 0:    0 = 16bit program support only
  339.                        ;                       1 = 32bit program support
  340.                ;             bit 1..15 NOT USED
  341.                ;        CL = processor type 02h= 80286
  342.                ;                    03h= 80386
  343.                ;                            04h= 80486
  344.                ;                            05h= Pentium ?
  345.                ;                            06h..0FFh = not used
  346.                ;        DH = DPMI version major number (binary)
  347.                ;        DL = DPMI version minor number (binary)
  348.                ;           [386power fully supports DPMI 0.9 and 1.0]
  349.                ;        SI = number of paragraphs required for
  350.                ;         DPMI host private data (it may be 0)
  351.                ;        ES:DI = segment:offset of procedure to call
  352.                ;                to enter protected mode
  353.  
  354.     int 2fh        ;
  355.     or ax,ax       ;
  356.     jz StartDPMI   ; Go DPMI if present
  357.         
  358.         say msg_VCPItest
  359.         ; Not DPMI, try VCPI.
  360.         ; Because of the new EMM386 from DOS 6.0 and above
  361.         ; we have to test for VCPI services only
  362.         ; (on old EMM386 versions this may spell troubles if EMS support
  363.         ;  is not enabled)
  364.  
  365.         pop  es ;  restore es for safety
  366.  
  367.         xor eax,eax
  368.         mov gs,ax ; gs == segment zero
  369.         cmp eax,gs:(4*67h) ; NULL vector ?
  370.         je short NotIntoVCPI
  371.         mov ax,0de00h       ;
  372.         int 67h             ;  Call VCPI INSTALLATION CHECK
  373.         or ah,ah            ;
  374.         jnz short NotIntoVCPI   ; if (ah != 0) it isn't VCPI
  375.         jmp StartVCPI
  376. NotIntoVCPI:
  377.         pushfd
  378.         pop eax
  379.         test eax,20000h
  380.         jz try_xms  ; if not into V86 mode, try real mode XMS startup
  381.         ; No other VMM is supported
  382.         mov dx,offset em2_unkV86
  383.         jmp short exit16err
  384. try_xms:
  385.         ; now check for XMS (this is the best environment
  386.         ; you can use, good hardware indipendence, irq reflection
  387.         ; and maximum speed)
  388.         ; set XMS/HARD "switch to real mode" functions
  389.         mov _ExecINT,offset s32_ExecINT
  390.         mov _ExecReal,offset s32_ExecReal
  391.         say msg_XMStest
  392.         mov ax,4300h
  393.         int 2Fh
  394.         cmp al,80h
  395.         jne NotIntoXMS
  396.         jmp StartXMS
  397. NotIntoXMS:
  398.         ; Aww! We have to try to run on basic hardware and bios.
  399.         ; Maybe we'll hang up if this system is not enough compatible
  400.         say msg_HARDtest
  401.         jmp StartHARD
  402.         
  403. ;------------------------------------------------------------------------------
  404.  
  405. InitAlloc:  
  406.         ; Allocate low memory or die. (called from initialization code)
  407.     ; EAX=space to allocate
  408.         push ebx
  409.         add eax,_LoMemBase
  410.         mov ebx,_LoMemTop
  411.         cmp ebx,eax            ; gone above _LoMemTop ?
  412.         jb short noinitmem     ;
  413.         sub  ebx,eax
  414.         xchg eax,_LoMemBase
  415.         cmp ebx,LOWMIN*1024  ; gone above lower memory limit of
  416.         jb short noinitmem   ; free memory reserved for program data ?
  417.         pop ebx
  418.         ret
  419. noinitmem:
  420.         mov dx,offset emINI_no_lomem
  421.         ; join error report & exit routine
  422. exit16err:
  423.         mov ah,09       ; Tell what's gone wrong and get out
  424.     int 21h
  425.  
  426.         say emX_stderr
  427.         jmp ds:exitrout
  428.  
  429. exit:   ; Good Old terminate program function (default exitrout)
  430.         ; for real mode termination or the final VCPI shutdown
  431.         ; (DPMI shutdown goes thru a different route)
  432.         ; restore interrupts before getting out
  433.         say msg_rints
  434.         ; now restore interrupts
  435.         mov si,offset _OldInt
  436.         mov ax,02500h
  437.         push ds
  438.         pop es
  439. setints:
  440.         mov dx,es:[si]
  441.         mov ds,es:[si+2]
  442.         add si,4
  443.         int 21h
  444.         inc al
  445.         jnz setints
  446.         push es
  447.         pop ds
  448.         sti
  449.         say msg_end
  450.         mov ax,4C00h ; terminate this program
  451.     int 21h
  452.  
  453. ; 16 bit common system code starts here
  454.  
  455. ; INTREAL  & CALLREAL
  456. ; temporary INT to real mode OR temporary CALL FAR to real mode.
  457. ; CALLS TO INTREAL OR CALLREAL ARE PERFORMED FROM CODE32 SWITCHPOINTS
  458. ; SO WHEN THE CPU GETS HERE THE MODE SWITCH HAS ALREADY BEEN DONE.
  459.         align byte
  460.  
  461. intreal:; temporary far call to real mode WITH INTERRUPT STACK FRAME
  462.         ; tempaddr contains the far address of the interrupt to call
  463.         ; SIMULATE INTERRUPT STACK FRAME
  464.         pushf                 ; FLAGS
  465. callreal:
  466.         ; temporary far call to real mode , NOW in 16bit mode
  467.         ; SIMULATE CALL FAR STACK FRAME with INTERRUPTS DISABLED
  468.         ; tempaddr contains the far address of the routine to call
  469.         push cs                 ; CS
  470.         push (offset exec_done) ; IP
  471.  
  472.         push dword ptr tempaddr ;address to call
  473.  
  474.         ; load virtual registers and jump to real-mode code to execute
  475.         mov fs,V86fs         ; load Vregs
  476.         mov gs,V86gs         ;
  477.         mov es,V86es         ;
  478.         ; ss:esp      set by mode switch code
  479.         mov eax,V86eax       ;
  480.         mov ecx,V86ecx       ;
  481.         mov edx,V86edx       ;
  482.         mov ebx,V86ebx       ;
  483.         mov esi,V86esi       ;
  484.         mov edi,V86edi       ;
  485.         mov ebp,V86ebp       ;
  486.         mov ds,V86ds
  487.         retf ; jmp to tempaddr
  488. exec_done: ; done with real mode interrupt/call
  489.         cli
  490.         push eax
  491.         push ds
  492.         mov ax,code32
  493.         mov ds,ax  ; save returned ds segment
  494.         pop ax
  495.         mov V86ds,ax
  496.         pop V86eax
  497.         pushf    ; save flags
  498.         pop V86F ;
  499.         mov V86ecx,ecx
  500.         mov V86edx,edx
  501.         mov V86ebx,ebx
  502.         mov V86esi,esi
  503.         mov V86edi,edi
  504.         mov V86ebp,ebp
  505.         mov V86es,es
  506.         mov V86fs,fs
  507.         mov V86gs,gs
  508. IREAL_TERMINATOR:
  509.         jmp word ptr ds:[s16_irToSYS32]
  510.  
  511. ; here follows the two possible "switchpoints" pointed by s16_irToSYS32
  512.  
  513. irToVCPI32:  ; VCPI return to 386P
  514.         mov v16_sw_dest,offset v32_exec_d ; jump to end of 386P INT32/33
  515.         mov esi,v16_VCPIsys               ; system data for mode switch
  516.         mov ax,0de0ch   ; SWITCH TO PROTECTED MODE thru VCPI
  517.         int 67h         ;
  518.         
  519. irToDPMI32: ; DPMI return to 386P
  520.         mov ebx,s32_SavStackOfs ;
  521.         mov dx,s32_SavStackSel  ; get 386P stack in dx:ebx
  522.         mov cx,dx                  ; cx  = current stack seg. (same of 386P)
  523.         mov si,_SelCode            ; si  = new code sel
  524.         mov edi,offset d32_16done  ; edi = new code offset
  525.         mov ax,_SelData            ; ax  = new data sel
  526.         jmp ds:d16_Fast16_To_32       ; mode switch routine
  527.  
  528. irToHARD32:
  529.         mov esi,08h                 ; _SelCode
  530.         mov edi,offset s32_exec_d   ; s32_exec_d
  531.         jmp HARD_R2P
  532.  
  533. ;-----------------------------------------------------------------------------
  534. ; real mode "foot" of VCPI irq-from-protected-mode reflector
  535. ;-----------------------------------------------------------------------------
  536.         align byte
  537. v16_irqreal:
  538.         ; VCPI real mode IRQ from 32bit prot. mode
  539.         ; fast irq response without copying virtual registers
  540.         ; ebp= ISR to call
  541.         cli
  542.         pushf                              ;  iret stack frame
  543.         push cs                            ;
  544.         push (small offset irqrealToVCPI32);
  545.         push ebp ; address of real mode isr
  546.         retf
  547. irqrealToVCPI32:  ; VCPI return to 386P
  548.         mov v16_sw_dest,offset v32_irqret ; jump to end of irq reflection
  549.         mov esi,v16_VCPIsys   ; system data for mode switch
  550.         mov ax,0de0ch   ; SWITCH TO PROTECTED MODE thru VCPI
  551.         int 67h         ;
  552.  
  553. ;-----------------------------------------------------------------------------
  554. ; real mode "foot" of HARD/XMS irq-from-protected-mode reflector
  555. ;-----------------------------------------------------------------------------
  556.         align byte
  557. s16_irqreal:
  558.         ; VCPI real mode IRQ from 32bit prot. mode
  559.         ; fast irq response without copying virtual registers
  560.         cli
  561.         pushf                              ;  iret stack frame
  562.         push cs                            ;
  563.         push (small offset irqrealToHARD32);
  564.         push ebp ; address of real mode isr
  565.         retf
  566. irqrealToHARD32:  ; HARD/XMS return to 386P
  567.         mov esi,08h                ; _SelCode
  568.         mov edi,offset s32_irqret  ; return IP
  569.         ; continue straight into HARD_R2P
  570. ;=============================================================================
  571. ; HARD/XMS real mode to protected mode switch
  572. ;=============================================================================
  573. HARD_R2P:
  574.         ; XMS/HARD real to protected switch
  575.         ; esi:edi == protected mode cs:eip to jump to
  576.         ; we suppose ss:sp is into 386P stack
  577.         ; IF IT IS NOT, set it there BEFORE SWITCHING!!!!!!!
  578.         ; eax modified
  579.         ; and
  580.         cli     ; clear irqs, this sequence is very critical
  581.                 ; so even the switch destination will have irq disabled
  582.  
  583.         lidt fword ptr s16_IDTaddr ; load protected mode IDT
  584.         lgdt fword ptr s16_GDTaddr ; load protected mode GDT
  585.         mov ax,10h ; code32 data selector
  586.         mov ds,ax                       ; load protected mode DS
  587.         mov es,ax                       ; load protected mode ES
  588.         mov fs,ax                       ; load protected mode FS
  589.         mov ss,ax  ; set prot mode stack segment
  590.  
  591.         mov ax,18h ;
  592.         mov gs,ax  ; load protected mode GS with _SelZero
  593.         mov eax,cr0    ; TURN ON PROTECTION
  594.         or al,1        ;
  595.         mov cr0,eax    ;
  596.         db 0EAh                        ; JMP FAR code32_selector:HARDPROT
  597.         dw small offset HARDPROT,08h   ;
  598.  
  599.  
  600. ;=============================================================================
  601. ; HARD/XMS protected mode to real mode switch
  602. ;=============================================================================
  603.  
  604.         align dword
  605.         dd 0
  606.         align byte
  607. HARD_P2R:
  608.         ; XMS/HARD PROTECTED MODE TO REAL MODE SWICTH
  609.         ; si,di == real mode destination
  610.         ; WE SUPPOSE SS:ESP is into 386P stack !!!!!!
  611.         ; If it is not (i.e. when performing irqs)
  612.         ; set it there before calling this!!!!!
  613.         ; only ss,cs and ds will be set correctly
  614.         ; EAX trashed
  615.  
  616.         cli
  617.         sub esp,Stack32BaseOffset ; convert to real mode stack offset
  618.  
  619.         lidt fword ptr s16_IDT86        ; load real mode IDT
  620.         mov ax,codeend
  621.         mov ss,ax
  622.         mov ax,code32
  623.         mov ds,ax
  624.         mov eax,cr0   ; TURN OFF PROTECTION
  625.         and al,0feh   ;
  626.         mov cr0,eax   ;
  627.         db 0EAh                      ; JMP FAR code16:intoreal
  628.         dw offset HARDREAL,code16    ; (flush pipeline)
  629. HARDREAL:
  630.         push si                         ; store real mode target CS
  631.         push di                         ; store real mode target IP
  632.         retf                            ; go to real mode destination
  633.  
  634. ;=============================================================================
  635. ; SET INT SLOTS TABLE
  636. ; BL=low PIC val, BH=high PIC val, 
  637. ; THE FIRST  16 INT SLOTS ARE THE IRQ INT SLOTS
  638. ; AND UNDER VCPI AND DPMI THEY CAN BE MAPPED ANYWHERE
  639.  
  640. setintslots:  ; set int slot table
  641.         push ecx
  642.         push ebx
  643.         push esi
  644.         mov si,offset intslotnum
  645.         mov cx,8
  646. setpicints:
  647.         mov [si],bl
  648.         mov [si+8],bh
  649.         inc si
  650.         add bx,0101h
  651.         dec cx
  652.         jne setpicints
  653.         pop esi
  654.         pop ebx
  655.         pop ecx
  656.         ret
  657.         
  658. ;--------------------------------------------------------------------------        
  659. ; DPMI 16 bit TERMINATION ROUTINE
  660.  
  661. d16_retreal: ; DPMI TERMINATE
  662.         ; Restore interrupts grabbed by DPMI interface
  663.         psay msg_pints
  664.         mov ax,0205h                   
  665.         xor bx,bx
  666.         mov edi,15 ; 16 ints for irqs
  667. d16_int_restore:
  668.         mov bl,intslotnum[di]
  669.         mov edx,dword ptr d32_OldInts[edi*8]
  670.         mov cx,word ptr d32_OldInts[edi*8+4]
  671.         int 31h
  672.         dec di
  673.         jns d16_int_restore  ; loop until less than zero
  674.         jmp d16_exit
  675.         
  676. d16_exit16err:    ; DPMI Exit with error message
  677.         mov V86ds,code32
  678.         mov V86ah,9
  679.         mov ax,0300h
  680.         mov bx,0021h
  681.         mov cx,0
  682.         mov edi,offset V86edi
  683.     push ds
  684.     pop es
  685.     int 31h
  686.  
  687. d16_exit:                                 ; DPMI exit to real mode
  688.         mov es,d16_PSPSel                 ; restore env selector
  689.         mov ax,d16_DosEnvSegSel
  690.     mov es:[2ch],ax
  691.  
  692.         ; TERMINATE PROGRAM
  693.         ; but restore interrupts before getting out
  694.         ; using the DPMI API function
  695.         psay msg_rints
  696.         mov si,offset _OldInt
  697.         mov ax,0201h
  698.         mov bl,00
  699. dsetints:
  700.         mov dx,[si]
  701.         mov cx,[si+2]
  702.         add si,4
  703.         int 31h
  704.         inc bl
  705.         jnz dsetints
  706.         ; Now terminate program
  707.         sti
  708.         psay msg_end
  709.  
  710.         ; Time to unlock the memory we tried to lock a startup
  711.         psay msg_unlock
  712.         mov esi,hidpmi_size
  713.         mov ax,0601h
  714.         mov ebx,hidpmi_base
  715.         mov di,si
  716.         mov cx,bx
  717.         shr esi,16
  718.         shr ebx,16
  719.         int 31h
  720.         ; we don't need to check for failure
  721.  
  722.         ; NOW RELEASE EXTENDED MEMORY BLOCK
  723.         psay msg_releasemem
  724.         mov esi,hidpmi_handle
  725.         mov ax,0502h
  726.         mov di,si
  727.         shr esi,16
  728.         int 31h
  729.         ; we don't need to check for failure
  730.  
  731.         ; now we can free the selectors
  732.         psay msg_DPMIrzero32
  733.         mov ax,0001h
  734.         mov bx,_SelZero
  735.         int 31h
  736.         psay msg_DPMIrcode32
  737.         mov ax,0001h
  738.         mov bx,_SelCode
  739.         int 31h
  740.  
  741.         mov ss,_EXIT_SS     ; change stack so we don't use _SelData anymore
  742.         mov esp,_EXIT_ESP   ;
  743.  
  744.         psay msg_DPMIrdata32
  745.         mov ax,0001h
  746.         mov bx,_SelData
  747.         int 31h
  748.         ; terminate
  749.         psay msg_DPMIfinal
  750.         mov ax,4C00h
  751.         int 21h
  752.  
  753. StartDPMI:  ; DPMI initialization
  754.         mov _386Man,IS_DPMI           ; set system type DPMI byte
  755.         mov _ExecINT,offset d32_ExecINT
  756.         mov _ExecReal,offset d32_ExecReal
  757.         pop gs ; get previous PSP segment into GS
  758.  
  759.         ; modify code switchpoint
  760.         mov s16_irToSYS32, offset irToDPMI32
  761.  
  762.         test bl,1                       ; test if 32bit DPMI server
  763.     mov dx,offset em7_noDPMI32      ;
  764.     jz exit16err                    ;
  765.  
  766.         xor eax,eax    ;
  767.         mov ax,si      ; get mem for DPMI block
  768.         
  769.         mov d16_EnterDPMI,di               ; store enter protected mode addr
  770.         mov ds:(2+offset d16_EnterDPMI),es ;
  771.         
  772.         inc eax ; add an extra paragraph to dpmi mem block for security
  773.         
  774.         push word ptr gs:[2ch]   ; preserve environment segment
  775.                                  ; located into PSP
  776.  
  777.     ; NOW GET READY TO ENTER 16BIT PROTECTED MODE
  778.         ; remember, eax = paragraphs needed for DPMI private data
  779.  
  780.     shl eax,4         ;
  781.     call InitAlloc    ;
  782.     shr eax,4         ;
  783.         add ax,code32     ;
  784.     mov es,ax         ; es:0000 = base of DPMI private data
  785.  
  786.         mov ax,0001h      ; This is a 32bit application
  787.                           ; so turn on 32bit register interface
  788.                           
  789.         call dword ptr ds:d16_EnterDPMI
  790.         
  791.     ; NOW IN 16 BIT PROTECTED MODE
  792.         ; (we are into code16 for code and code32 for data )
  793.         ; PSP:[2ch] now is a SELECTOR to the environment space
  794.         ; cs,ds,ss are now SELECTORS equivalent to their 
  795.         ; previous real-mode segment values.
  796.         ; es contains the PSP selector
  797.         ; fs,gs are set to zero
  798.         
  799.         cli ; Better don't trust DPMI , clear interrupts again
  800.  
  801.         mov V86dx,offset msg_DPMIifail    ;
  802.         jc d16_exit16err                  ; Initialization ok?
  803.  
  804.         pop ax             ; swap environment segment  with equivalent selector
  805.         xchg ax,es:[2ch]   ; now pspa+2ch == environment REAL segment
  806.                            ; we use this trick because VCPI
  807.                            ; startup code doesn't set up selectors for PSP
  808.                            ; so we "standardize" on real-mode segments
  809.                            ; instead of pmode selectors
  810.  
  811.         mov d16_DosEnvSegSel,ax  ; store DPMI ENVIRONMENT selector
  812.  
  813.         mov d16_PSPSel,es        ; store PSP selector
  814.  
  815.         push ds                  ; no more need for PSP segment
  816.         pop es                   ; now ES == DS
  817.  
  818.         mov _EXIT_DATA_SEL,ds                    ;
  819.         mov _EXIT_SEL,cs                         ;
  820.         mov _EXIT_ADDR,large offset d16_retreal  ; set program termination data
  821.         mov _EXIT_SS,ss
  822.  
  823.         mov _SetIRQ,offset d32_setirq  ; set new IRQ managers
  824.         mov _GetIRQ,offset d32_getirq  ;
  825.  
  826.     ; MUST ASK DPMI FOR VALID SELECTORS
  827.     mov ax,0003   ; get selector increment value
  828.     int 31h       ;
  829.     mov bx,ax     ;
  830.  
  831.     mov ax,0000   ; get base selector for a list of 3 selectors
  832.         mov cx,3      ; cx= number of selector to allocate in LDT
  833.     int 31h       ;
  834.         mov V86dx, offset em8_DPMIdesc
  835.         jc d16_exit16err
  836.     ; set up descriptors
  837.     ;  bx= selector increment  ,  ax = first selector value
  838.  
  839.         
  840.  
  841.     ; INITIALIZE & STORE SELECTORS
  842.         mov si,ax                       ; si = _SelCode selector
  843.         mov _SelCode,ax                ; store segment selectors
  844.         
  845.         lea ecx,[eax+ebx]               ; cx = _SelData selector
  846.         mov _SelData,cx                ; store segment selectors
  847.         
  848.         lea ebp,[ecx+ebx]               ; bp = _SelZero selector
  849.         mov _SelZero,bp                ; store segment selectors
  850.         
  851.         psay msg_DPMIlar
  852.         ; WARNING! THIS CAN BE DANGEROUS!!! 
  853.         mov dx,cs   ;
  854.         cmp dx,dx   ; set zero flag so we will know if LAR set it to zero
  855.         lar dx,dx   ;
  856.         jnz badlar
  857.         and dh,060h ; access rights AND CPL 3
  858.                     ; (just in case we find a DPMI server running
  859.                     ;  in more powerful cpu levels :) )
  860.         jmp short desclink
  861. badlar: ;Failed loading access rights
  862.         psay msg_DPMIbadlar
  863.         mov dh,060h
  864. desclink:
  865.         clc ; clear carry
  866.             ; to be sure only the following int 31h will modify it
  867.  
  868.         ; NOW LINK THE DESCRIPTORS TO THEIR SELECTOR INTO LDT
  869.         ; and with the same CPU LEVEL of the cs set by dpmi init routine
  870.         psay msg_DPMIcode32
  871.         ; set error message if selector modification fails
  872.         mov V86dx,offset em9_DPMImod
  873.         mov ax,000ch                      ; COPY descriptors into DPMI LDT
  874.                       ; ax = 000ch
  875.                       ; bx     = selector value
  876.                       ; ds:edi = pointer to the 8 bytes
  877.                       ;          of data to COPY into
  878.                       ;          the descriptor into GTD
  879.  
  880.     mov bx,si                         ;
  881.         mov edi,offset GDTcode32          ;
  882.         or byte ptr [edi+5],dh            ; change CPL
  883.     int 31h                           ;
  884.         jc d16_exit16err                  ;
  885.  
  886.         psay msg_DPMIdata32
  887.         ; set error message if selector modification fails
  888.         mov V86dx,offset em9_DPMImod
  889.         mov ax,000ch
  890.     mov bx,cx                         ;
  891.         mov edi,offset GDTdata32          ;
  892.         or byte ptr [edi+5],dh            ;
  893.     int 31h                           ;
  894.         jc d16_exit16err                  ;
  895.  
  896.         ; SET SEGMENT REGISTERS TO 32BIT ADDRESSING
  897.         mov ds,cx    ;
  898.         mov es,cx    ;
  899.         mov fs,cx    ; DS,ES,FS = Data32 (alias for Code32)
  900.  
  901.         psay msg_DPMIzero32
  902.         ; set error message if selector modification fails
  903.         mov V86dx,offset em9_DPMImod
  904.         mov ax,000ch
  905.     mov bx,bp                         ;
  906.         mov edi,offset GDTzero32          ;
  907.         or byte ptr [edi+5],dh            ;
  908.     int 31h                           ;
  909.         jc d16_exit16err                  ;
  910.         
  911.         ; SET "LINEAR" segment GS
  912.         mov gs,bp    ; GS = selector to linear addressing base
  913.  
  914.     ; CHECK IF THERE IS ENOUGH LOW MEMORY FOR PROGRAM DATA
  915.         ; AND DPMI TABLES
  916.         mov edi,_LoMemBase
  917.         mov eax,_LoMemTop
  918.     sub eax,edi
  919.         cmp eax,48  ; minimum space needed for extended info
  920.         mov V86dx,offset em1_no_lomem
  921.         jb d16_exit16err
  922.          
  923.         mov _HiMemBase,0  ; better assume the worst
  924.         mov _HiMemTop ,1  ;
  925.         psay msg_DPMIhiget
  926.         mov eax,EXTMIN
  927.         or eax,eax
  928.         jnz getminfo
  929.         jmp DPMI_state ; if no ext. mem required, go to set to_DPMI_state
  930. getminfo:
  931.         ; DPMI 00.90  ext. memory allocation
  932.         ; initially my code checked for DPMI version numbers
  933.         ; but found some inconsistent major release numbers
  934.         ; so decided to support only the lowest common denominator (DPMI 0.9)
  935.         mov ax,0500h             ;  ax     = 0500 == GET DPMI INFO 0.9
  936.         int 31h                  ;  es:edi = info block  (48 bytes wide)
  937.                                  ;  remember edi was set on _LoMembase
  938.         mov V86dx,small offset msg_DPMInominfo
  939.         jc d16_exit16err
  940.  
  941.         mov edx,es:[edi+08h]  ; largest available lockable page number
  942.         cmp edx,-1            ; (1page = 4K)
  943.         je  short DPMIdefault_alloc
  944.         shl edx,12 ; allocate lockable pages
  945.         jmp short DPMIbyte_alloc
  946. DPMIdefault_alloc:        
  947.         mov edx,(EXTMIN*1024)  ; minimum space in Kbyte
  948. DPMIbyte_alloc:
  949.         mov V86dx,offset em3_no_himem
  950.         cmp edx,(EXTMIN*1024)
  951.         jb d16_exit16err
  952.  
  953.         or edx,edx  ; zero bytes available ? go to next section
  954.         jnz gotobumper
  955.         jmp DPMI_state    ; no need for extended memory
  956. gotobumper:
  957.         ; ALLOCATE EXT. MEMORY THRU DPMI
  958.         psay msg_allocmem
  959. d16_winbumper:
  960.   
  961.         push edx      
  962.     mov cx,dx                         ; in:
  963.         shld ebx,edx,16                   ; ax = 0501
  964.     mov ax,0501h                      ; bx:cx = ext. memory needed
  965.     int 31h                           ; out:
  966.         jnc d16_works                     ; CARRY CLEAR == NO ERRORS and ...
  967.         mov V86dx,offset em5_hifault      ; bx:cx = linear address allocated
  968.                                           ; si:di = memory block handle
  969.         ; Aw! Something has gone wrong! 
  970.         pop edx
  971.  
  972.         cmp edx,(EXTMIN*1024)
  973.         jbe d16_exit16err
  974.         sub edx,4096     ; try one page less, and see if it works
  975.         
  976.         jmp short d16_winbumper ; Usually Windows is to blame for this!
  977.  
  978. d16_works:
  979.         pop edx  ;get requested memory size back
  980.         shl esi,16
  981.         mov si,di
  982.         mov hidpmi_handle,esi
  983.         psay msg_lockmem
  984.         pushad
  985.         mov di,dx
  986.         shr edx,16
  987.         mov si,dx
  988.         mov ax,0600h
  989.         int 31h
  990.         jnc goodlock
  991.         psay msg_badlock
  992. goodlock:
  993.         popad
  994.         mov hidpmi_size,edx
  995.  
  996.         ; FROM VERSION 1.03 and up, no automatic locks are performed
  997.         psay msg_DPMIwin
  998.  
  999.         shl ebx,16            ;
  1000.         mov bx,cx             ;  ebx = memory block linear address
  1001.         mov hidpmi_base,ebx
  1002.         sub ebx,_Code32Base   ;
  1003.         mov _HiMemBase,ebx    ;
  1004.  
  1005.         add ebx,edx           ;
  1006.         mov _HiMemTop,ebx     ;  SET EXT MEM LIMITS
  1007.  
  1008. DPMI_state:
  1009.         ; ALLOCATE DPMI_SAVE_TASK_STATE BUFFERS AND POINTERS
  1010.  
  1011.     mov ax,0305h  ; get save/restore state addresses
  1012.     int 31h       ;
  1013.         mov V86dx,offset msg_DPMI_SR_FAIL
  1014.         jc d16_exit16err
  1015.  
  1016.         mov word ptr d32_StateBufferSize,ax  ; leght of save state block
  1017.  
  1018.     ; 32bit save/restore state  protected-mode routine
  1019.         mov  dword ptr d32_SaveRestoreState,edi               ; offset32
  1020.         mov  word ptr ds:(4+ offset d32_SaveRestoreState),si  ; seg32
  1021.  
  1022.     ; 16 bit save/restore state real-mode routine
  1023.         mov word ptr d16_SaveRestoreState,cx                 ; offset16
  1024.         mov word ptr ds:(2+ offset d16_SaveRestoreState),bx  ; seg16
  1025.  
  1026.     ; SET MODE SWITCH CODE POINTERS
  1027.  
  1028.     mov ax,0306h  ; get raw Mode Switch to 16<-->32 bit mode
  1029.     int 31h       ;
  1030.         mov V86dx,offset msg_DPMI_MS_FAIL
  1031.         jc d16_exit16err
  1032.  
  1033.     ; switch protected->real mode routine
  1034.         mov dword ptr d32_Fast32_To_16,edi                ; offset 32
  1035.         mov  word ptr ds:(4+ offset d32_Fast32_To_16),si  ; seg32
  1036.  
  1037.     ; switch real->protected mode routine
  1038.         mov word ptr d16_Fast16_To_32,cx             ; offset16
  1039.         mov word ptr ds:(2+ offset d16_Fast16_To_32),bx ; seg16
  1040.  
  1041.     ; NOW SET IRQs & INTs
  1042.  
  1043.     ; set IRQ handlers to PIC values
  1044.     mov ax,0400h ; Get DPMI version info
  1045.     int 31h      ; dh = 1st PIC base vector dl= 2nd PIC base vector
  1046.         mov V86dx,offset msg_DPMI_IV_FAIL
  1047.         jc d16_exit16err
  1048.  
  1049.     xchg dl,dh                    ;
  1050.     mov bx,dx                     ;
  1051.     call setintslots              ; set new vector table for IRQ
  1052.         
  1053.         psay msg_DPMIirq
  1054.         xor bx,bx
  1055.         mov si,_SelCode            ;
  1056.         mov edi,15                 ; 16 P.I.C ints
  1057.         mov ah,02 ; set higher byte of function code
  1058. DPMI_SavSetInts:
  1059.         mov bl,intslotnum[di]   ;
  1060.         mov al,04h                 ; ah was 02, so execute function 0204h
  1061.         int 31h                    ; GET PROT. MODE INT VECTOR bl
  1062.         mov V86dx,offset msg_DPMI_GI_FAIL
  1063.         jc d16_exit16err
  1064.         mov dword ptr d32_OldInts[edi*8],edx    ; save ints
  1065.         mov word ptr  d32_OldInts[edi*8+4],cx   ;
  1066.         
  1067.         mov al,05h                 ;
  1068.         mov edx,d16_nintoff[edi*4] ; ah was 02, so execute function 0205h
  1069.         mov cx,si                  ; SET PROT. MODE INT VECTOR bl
  1070.     int 31h                    ;
  1071.         mov V86dx,offset msg_DPMI_SI_FAIL
  1072.         jc d16_exit16err
  1073.         dec di               ; loop if greater or equal to zero
  1074.         jns DPMI_SavSetInts  ;
  1075.         psay msg_DPMIgood
  1076.         ; DPMI joins DPMI for 32bit init stuff
  1077.         push ds  ;
  1078.         pop  ss  ; ss = prot. mode 32bit selector
  1079.         add  esp,Stack32BaseOffset  ; esp = prot. mode stack base
  1080.         jmp JoinDPMI
  1081.  
  1082. ;-----------------------------------------------------------------------------
  1083. ; 16bit VCPI system code
  1084.  
  1085.         
  1086. ;------------------------------------------------------------------------------        
  1087. ; CALL TO prot. mode  : v16_sw_dest = offset to jump to in code32
  1088.         
  1089. v16_retreal:
  1090.         ; just returned to real mode from protected mode
  1091.         cli        
  1092.         ; if something fails, you get here ..
  1093. VCPI_exit: ; VCPI exit (clean up paging stuff)
  1094.         mov es,v16_PageDirSeg
  1095.         mov si,v16_PageBase
  1096.         mov cx,v16_PageTop
  1097.         
  1098.         sub cx,si          ; Need to deallocate VCPI memory pages ?
  1099.         
  1100.         jz short page_cleaned  ; No! Only remove EMS data
  1101.         ; Yes! Clean pages 
  1102.         say msg_VCPIfree
  1103. VCPI_clean:  ; Deallocate memory pages allocated thru VCPI
  1104.  
  1105.         mov edx,es:[si] ;
  1106.         and dx,0f000h   ;  edx == address of 4k page to deallocate & unlink
  1107.         
  1108.         mov ax,0de05h   ;  call page unlink function
  1109.         int 67h         ;
  1110.         
  1111.         add si,4 ; next page
  1112.         
  1113.         sub cx,4        ; loop if there are other pages to clean
  1114.         jnz VCPI_clean  ;
  1115. page_cleaned: ; now go to standard exit code
  1116.         jmp exit
  1117.         
  1118. VCPI_err1: ; VCPI not enough low mem exit
  1119.         mov dx,offset em1_no_lomem
  1120.         jmp exit16err
  1121.         
  1122. ;=============================================================================
  1123.         align byte
  1124. StartVCPI:
  1125.         mov _386Man,IS_VCPI ; set system type = VCPI
  1126.  
  1127.         ; set up mode switch linear pointers
  1128.         mov eax,_Code32Base       ; adjust mode-switch linear pointers
  1129.         add v16_VCPIsys,eax       ;
  1130.         add v16_sw_gdtaddrptr,eax ; from code32-relative offsets
  1131.         add v16_sw_idtaddrptr,eax ; to LINEAR addresses
  1132.         
  1133.         mov exitrout,offset exit ; set standard dos-cleanup exit
  1134.  
  1135.         
  1136.         ;-------------------------------------------------------------------
  1137.         ; NOW HANDLE PIC MAPPINGS
  1138.         say msg_VCPIpic
  1139.         mov ax,0de0ah   ; get PIC base vector mappings
  1140.         int 67h         ; BX,CX = first vector of master PIC and slave PIC 
  1141.         mov bh,cl       ; bh= now is first vector of slave PIC
  1142.         ; N.B. A single PIC uses 8 consecutive vector numbers
  1143.         ;      so you'd better avoid to use a vector base 30h
  1144.         ;      or your interrupts will "cover" the int 31h DPMI interface
  1145.         
  1146.         mov dx,offset em11_EqPIC ; set error message if something goes wrong
  1147.         
  1148.         ; Check for compatible PIC mapping ...
  1149.         cmp bl,bh
  1150.         je exit16err  ; Uh? Mapped as equal ? Whats that? Are you crazy ?
  1151.                       ; This is NOT for fucking old IBM XTs
  1152.                       
  1153.         mov dx,offset em6_PICfault ; set error message if something goes wrong              
  1154.         cmp bl,30h
  1155.         je exit16err  ; Low mapping clashes with service ints
  1156.         cmp bh,30h
  1157.         je exit16err  ; High mapping clashes with service ints
  1158.         
  1159.         ; search the highest interrupt number needed
  1160.         mov eax,33h         ; maximum int needed by 386p "without irqs"
  1161.                             ; and clear eax high word
  1162.  
  1163.         cmp al,bl           ;
  1164.         jnb short HIPIC1    ; skip if max int mapping >= master pic mapping
  1165.         mov al,bl           ; master pic has the highest mapping
  1166. HIPIC1:                     ; 
  1167.  
  1168.         cmp al,bh           ; 
  1169.         jnb short HIPIC2    ; skip if max int mapping >= slave pic mapping
  1170.         mov al,bh           ; slave pic has the highest mapping
  1171. HIPIC2:                     ;
  1172.  
  1173.         add al,7 ; add the 7 exceptions handlers 
  1174.                  ; to get the IDT SIZE
  1175.  
  1176.         ; AX = TOP INTERRUPT  NEEDED
  1177.  
  1178.         mov s16_Int_to_replace_ctr,ax  ; save number of ints to replace
  1179.         
  1180.         ; SET INT VECTOR TABLE
  1181.  
  1182.         lea eax,[eax*8+7]    ; set limit of IDT (every entry is 8 bytes)
  1183.         mov s16_IDTaddr,ax   ; and we need entries from 0 to ax
  1184.  
  1185.         ; bl,bh == int slots for master & slave PIC
  1186.         push eax
  1187.         call setintslots  ; remap irq int slots
  1188.         pop eax
  1189.         say msg_idt
  1190.         ;----------------------------------------------------------------------
  1191.         ; ALLOCATE SPACE FOR IDT
  1192.         call InitAlloc
  1193.         mov s32_idt32ptr,eax  ; save code32 idt pointer
  1194.         mov ebp,_Code32Base ;_Code32Base into ebp for immediate and later usage
  1195.         add eax,ebp                        ; get linear address of IDT
  1196.         mov dword ptr bases16_IDTaddr,eax  ; set IDT base address
  1197.  
  1198.         mov exitrout,offset VCPI_exit     ; set VCPI error&exit routine
  1199.         ;---------------------------------------------------------------------
  1200.         ; SET UP FIRST BLOCK OF PAGE TABLE AND PAGE DIRECTORY
  1201.         say msg_paging
  1202.         mov eax,_LoMemBase        ; align _LoMemBase on a 4k page
  1203.         lea eax,[ebp+eax+0fffh]   ; (ebp == _Code32Base )
  1204.         and eax,0fffff000h        ; ecx == _LoMemBase as LINEAR address
  1205.         mov ecx,eax    ; copy linear offset into ECX
  1206.         sub eax,ebp         ; linear_offset - _Code32Base
  1207.         mov _LoMemBase,eax  ; NOW _LoMemBase is 4KPAGE ALIGNED
  1208.                             ; so we can store page entries
  1209.                             ; and ecx contains the equivalent linear address
  1210.  
  1211.         
  1212.         mov ebp,_LoMemTop      ; get available low memory
  1213.         sub ebp,eax            ;
  1214.         sub ebp,LOWMIN*1024    ; die if not enough low memory
  1215.         jc VCPI_err1           ;
  1216.         cmp ebp,8192           ; die if no space for minimal page structure
  1217.         jb VCPI_err1           ;
  1218.  
  1219.         shr   ecx,4            ; set VCPI 386POWER page-directory segment
  1220.         mov v16_PageDirSeg,cx  ;
  1221.  
  1222.         ; The 8k allocated in low memory are split into
  1223.         ; 1) a 4K (1000h) PAGE DIRECTORY 
  1224.         ; 2) a 4k PAGE TABLE (the first page table, others are chained to it)
  1225.  
  1226.         mov es,cx                   ; reset all addresses
  1227.         xor edi,edi                 ;
  1228.         mov cx,2048                 ;
  1229.         xor eax,eax                 ;
  1230.         rep stosd                   ;
  1231.  
  1232.         ;--------------------------------------------------------------------
  1233.         ; GET VCPI 32BIT INTERFACE
  1234.         ; AND INITIALIZE SHARED PAGES' ENTRIES
  1235.         say msg_VCPIhookserver
  1236.         mov di,1000h ; es:di == pointer to FIRST PAGE TABLE
  1237.                      ; (vcpi inits it with the pages already allocated)
  1238.                      ; (the page directory initalization is up to us)
  1239.                      
  1240.         mov si,offset GDTvcpi    ; Get Vcpi Protected Mode Interface
  1241.         mov ax,0de01h            ; in:    ax = 0de01h
  1242.         int 67h                  ;  es:di = ptr to 4k page table buffer
  1243.                                  ;  ds:si = ptr to 3 descriptor table entries 
  1244.                                  ;          the first becomes the
  1245.                                  ;          code segment descriptor
  1246.                                  ;          the other two are used by
  1247.                                  ;          the MAIN CONTROL PROGRAM
  1248.                                  ; out:  ebx = offset of prot. mode entry point
  1249.                                  ;             (relative to GDTvcpi)
  1250.                                  ;       es:di = first unused page table entry
  1251.                                  ;               in page table buffer
  1252.                                   
  1253.         mov dword ptr v32_vcpientryaddr,ebx  ;store entry offset
  1254.                                              ;into fword
  1255.         
  1256.         ; DI = end of allocated entries on page table
  1257.         ; ONE ENTRY takes 4 bytes, one entry maps a 4k page
  1258.         ; so if you subtract the page base offset (1000h)
  1259.         ; DI is EXACTLY how many Kbytes has been allocated by VCPI
  1260.         ; starting from "your task" linear address 00000000h
  1261.         
  1262.         mov v16_PageBase,di      ; set the starting position of blocks
  1263.         mov v16_PageTop,di       ; not allocated automatically by VCPI
  1264.         ;( the automatically allocated ones are handled by VCPI
  1265.         ;  while the other ones will be up to us )
  1266.         
  1267.         movzx eax,di           ;  
  1268.         sub eax,1000h          ;
  1269.         shl eax,10             ;  eax = base of extended memory in bytes
  1270.         
  1271.         mov ebp,_Code32Base ;
  1272.         
  1273.         sub eax,ebp         ;
  1274.         mov _HiMemBase,eax  ;  set initial _HiMemBase value
  1275.         
  1276.         ; NOW SET EBX AS A COUNTER OF THE BYTES ALLOCATED
  1277.         ; IN LOW MEMORY FOR PAGING INFO
  1278.         mov ebx,8192           ; one page directory + one page table
  1279.         add ebx,_LoMemBase     ; + _LoMemBase = pointer beyound last byte
  1280.                                ;                used by paging tables
  1281.         say msg_VCPIaddpages
  1282. page_table_alloc:                      
  1283.         mov ax,0de04h          ; Allocate one page, ax =0de04h
  1284.         int 67h                ; out: ah = error code ( 00 == no errors)
  1285.         or ah,ah               ;     edx = linear address of allocated page
  1286.         jnz short end_page_alloc    
  1287.         
  1288.         test di,0fffh             ; Check if at end of page table
  1289.         jnz short not_4k_boundary ;
  1290.         ; else advance one page
  1291.         add ebx,4096        ; add space for another 4k page table
  1292.  
  1293.         cmp ebx,_LoMemTop    ; run out of low memory ?
  1294.         jnb VCPI_err1        ;
  1295.         
  1296. not_4k_boundary:                      
  1297.         and dx,0f000h          ; Mark this page as one-page-block
  1298.         or dl,7                ; present,user,read/write
  1299.         mov es:[di],edx        ; store entry on page table
  1300.         add di,4               ;
  1301.         cmp di,(65536-4096)
  1302.         jb page_table_alloc   ; STOP if allocated 64k-4k of mapping ram
  1303.                               ; (equivalent to 64-4-4 ==  56 megabytes
  1304.                               ;  due to the first 4k block used by the page dir
  1305.                               ;  and to the last 4M used for phys mapping)
  1306.         
  1307. end_page_alloc:                         
  1308.         mov v16_PageTop,di ; Store final allocated page table limit
  1309.         ; beyound v16_PageTop there will be the "extra mappings"
  1310.         ; available for mapping of devices
  1311.  
  1312.         ; now...  read carefully:
  1313.         ; a single page entry maps 4kbytes
  1314.         ; and uses 4 bytes
  1315.         ; so the space used by page entries
  1316.         ; is equivalent to the linear addresses in kbyte multiples
  1317.         ; IF YOU EXCLUDE THE SPACE USED BY THE PAGE DIRECTORY TABLE
  1318.  
  1319.         lea si,[di-1000h] ; (1000h == 4096) 1000h = space used by the page dir
  1320.                           ; will be used later
  1321.  
  1322.         movzx eax,si      ;
  1323.         shl eax,10        ; eax = LINEAR address of allocated ext. mem. limit
  1324.         
  1325.         sub eax,ebp             ; EBP is still_Code32Base
  1326.         mov _HiMemTop,eax       ; store _HiMemTop value
  1327.         
  1328.         ; PHYS MAPPING STUFF
  1329.         mov _MapMemBase,eax   ; store base of mappable phys ram
  1330.         add eax,(4*1024*1024) ; 4MegaByte
  1331.                               ; Don't touch this, it is hard to fix
  1332.                               ; all the references to this 4M limit
  1333.                               ; if you don't coded it. (sorry)
  1334.  
  1335.         mov _MapMemTop,eax ; store limit of mappable ram
  1336.  
  1337.         movzx eax,v16_PageDirSeg
  1338.         and edi,0000FFFFh  ; clear upper word
  1339.         shl eax,4
  1340.         add eax,edi
  1341.         sub eax,_Code32Base   ; this is a code relative offset
  1342.         mov _PhysMapTable,eax
  1343.  
  1344.         
  1345.         
  1346.         sub di,v16_PageBase        ;
  1347.         cmp di,EXTMIN              ;
  1348.         mov dx,offset em3_no_himem
  1349.         jb exit16err
  1350.         
  1351.         add ebx,4096            ; add the mappable mem block
  1352.  
  1353.         mov _LoMemBase,ebx      ; move _LoMembase beyound paging data
  1354.         ;----------------------------------------------------------------------
  1355.         ; NOW WE SET THE CR3 PAGE DIRECTORY REGISTER VALUE
  1356.         say msg_VCPIpagedir
  1357.  
  1358.         movzx eax,v16_PageDirSeg ; 
  1359.         shl   eax,4              ; page_dir segment as linear address
  1360.         mov v16_sw_cr3,eax                ; SET PAGE REGISTER
  1361.  
  1362.         ;----------------------------------------------------------------------
  1363.         ; now set up PAGE DIRECTORY
  1364.         ;
  1365.         mov   ebx,4096   ; PAGE SIZE
  1366.         xor di,di   ; es:di == page directory address
  1367.         ; si = allocated space for page tables
  1368. set_page_directory:
  1369.         add eax,ebx      ; next page table address
  1370.         and ax,0f000h    ; Why this ? because we need to keep "paging flags"
  1371.         or al,7          ; clean (for vcpi compatibility) except the needed ones
  1372.         stosd            ; store into page table location of page dir. entry
  1373.         sub si,bx ; 4Mbytes has been mapped in a single page dir entry
  1374.         jnbe set_page_directory
  1375.         add eax,ebx      ; 4M "physical mappings" page table address
  1376.         and ax,0f000h    ; Why this ? because we need to keep "paging flags"
  1377.         or al,7          ; clean (for vcpi compatibility) except the needed ones
  1378.         stosd            ; store into page table location of page dir. entry
  1379.  
  1380.         ;----------------------------------------------------------------------
  1381.         ; TSS SETUP
  1382.         ;
  1383.         say msg_tss
  1384.         mov eax,68h   ; TSS is 68h bytes wide
  1385.         call InitAlloc; allocate space for TSS and IDT
  1386.         add eax,_Code32Base ; get linear address of TSS
  1387.  
  1388.         ; set Task Switch Segment (TSS) descriptor base address
  1389.         or dword ptr baseGDTtask,eax
  1390.  
  1391.         mov ebx,eax
  1392.         shr eax,4
  1393.         mov es,ax
  1394.         and ebx,0Fh
  1395.         ;  es:bx = TSS start
  1396.  
  1397.         ; first of all, clear everything (i'm paranoid)
  1398.         mov di,bx    ; clear TSS and IO bitmap
  1399.         xor eax,eax  ;
  1400.         mov ecx,1Ah  ; TSS size in dwords
  1401.         rep stosd    ; T-bit is cleared into this loop
  1402.  
  1403.         ; then set IObitmap position, so the server will know there is not
  1404.         mov byte ptr es:[bx+66h],68h ; 68h == end of tss
  1405.  
  1406.         mov eax,v16_sw_cr3
  1407.         mov es:[bx+1Ch],eax ; set CR3 in TSS (i'm paranoid)
  1408.  
  1409.         say msg_VCPIkick
  1410.         ;---------------------------------------------------------------------
  1411.         ; ENTER 16BIT PROTECTED MODE
  1412.         mov v16_sw_dest,offset VCPI_protected16 ; offset to jump to in 386P
  1413.         mov ax,0de0ch   ; SWITCH TO 16bit PROTECTED MODE thru VCPI      
  1414.         mov esi,v16_VCPIsys   ; system data for mode switch
  1415.         int 67h         ; GO!
  1416.         
  1417. VCPI_protected16:        ; in 16bit prot. mode
  1418.         ; Now set 32 bit protected mode segments and stack pointer
  1419.         ; for VCPI
  1420.         cli
  1421.         mov ax,18h ;
  1422.         mov gs,ax  ; gs= linear
  1423.         
  1424.         mov ax,10h ;  ds,es,fs,ss = data32
  1425.         mov ds,ax  ;
  1426.         mov es,ax  ;
  1427.         mov fs,ax  ;
  1428.         mov ss,ax  ;
  1429.         
  1430.         mov esp,(STACKSIZE*16)     ; esp set at stack start in 16bit mode
  1431.         add esp,Stack32BaseOffset  ; esp = prot. mode stack base
  1432.         
  1433.         ; now set up 32bit mode completely
  1434.  
  1435. VCPI_ready32:
  1436.         ; First switch was from 16bit real to 16bit prot. CODE SEG
  1437.         ; next switches will be from 16bit prot. to 32bit prot. CODE SEG
  1438.         ; so, set 32bit seg selector into mode switch table
  1439.         mov word ptr ds:(4+ offset v16_sw_dest),08h ; _SelCode
  1440.  
  1441.         ; now initialize IDT with general exception handler
  1442.         mov edi,s32_idt32ptr; get code32 relative ptr to IDT
  1443.         ; now EDI == base pointer to IDT
  1444.         
  1445.         ; set general exception handler
  1446.         ; into ALL SLOTS OF VCPI CLIENT INTERRUPT TABLE
  1447.         ; (default reaction to "unknown interrupt" is auto-reset)
  1448.         xor esi,esi ; clear esi
  1449.         mov si,s16_Int_to_replace_ctr
  1450.         
  1451.         mov eax,offset s32_exc  ; set the generic exception handler as default
  1452.         and eax,0000ffffh       ; offset s32_exc (we know it's under 64k)
  1453.         or  eax,00080000h       ; code32 pmode selector
  1454.         
  1455.         mov ebp,00008E00h       ; flags & higher (clear) offset
  1456.                                 
  1457.         ; IDT entry (8 bytes)
  1458.         ; offset  size
  1459.         ;      0     2   low offset  of ISR (Interrupt Service Routine)
  1460.         ;      2     2   selector    of ISR
  1461.         ;      4     2   flags
  1462.         ;      6     2   high offset of ISR
  1463.         
  1464. SetIDTEntry:
  1465.         ; selector = 8
  1466.         ; offset    = offset s32_exc (generic handler)
  1467.         mov [edi+esi*8],eax ; offset basso e selettore
  1468.         mov [edi+esi*8+4],ebp ; flags & offset alto azzerato
  1469.         dec si
  1470.         jns SetIDTEntry
  1471.         
  1472.         ; NOW IT'S TIME TO SET INTO THE INTERRUPT TABLE
  1473.         ; THE OFFSETS OF THE ISR ROUTINES WE SUPPORT
  1474.         ; copy exception handlers from IDT
  1475.         mov esi,16 ; 16 irq + 1 "DPMI api interrupt"
  1476.         xor ebx,ebx
  1477. SetIDTInt:
  1478.         mov bl,intslotnum[si]
  1479.         mov eax,[esi*4+v16_idt_default] ; get ISR offset from v16_idt_default
  1480.         mov [edi+ebx*8],ax ; put it into the correct idt slot
  1481.                            ; (because we know it fits into 16bit
  1482.                            ;  we don't set the higher word)
  1483.         mov [esi*8+ s32_irqtable],eax
  1484.                                   ; put it into the irq table
  1485.                                   ; (default values are the XMS/HARD ones)
  1486.         dec si
  1487.         jns SetIDTInt
  1488.         
  1489.         ; HERE WE GO TO 32bit PROTECTED MODE
  1490.         pushfd               ; set eflags: NT=0
  1491.         pop eax              ;
  1492.         and ah,0bfh          ;
  1493.         push eax             ;
  1494.         popfd                ;
  1495. ; READY TO ENTER 32BIT PROTECTED MODE
  1496.         align byte
  1497. JoinDPMI: ; shared by VCPI & DPMI
  1498.           ; NOW WE CAN ENTER 32BIT PROTECTED MODE
  1499.  
  1500.         mov ax,_SelCode
  1501.         mov word  ptr ds:(4 + offset Kick32),ax
  1502.         jmp fword ptr ds:Kick32
  1503.  
  1504. ;==============================================================================
  1505. ; 16 bit VCPI redirectors
  1506.  
  1507. ; VCPI real mode irq reflector to prot mode
  1508.  
  1509. v16_virqf:
  1510.         push ecx
  1511.         mov  ecx,15*4
  1512.         jmp v16_virq
  1513. v16_virqe:
  1514.         push ecx
  1515.         mov  ecx,14*4
  1516.         jmp v16_virq
  1517. v16_virqd:
  1518.         push ecx
  1519.         mov  ecx,13*4
  1520.         jmp short v16_virq
  1521. v16_virqc:
  1522.         push ecx
  1523.         mov  ecx,12*4
  1524.         jmp short v16_virq
  1525. v16_virqb:
  1526.         push ecx
  1527.         mov  ecx,11*4
  1528.         jmp short v16_virq
  1529. v16_virqa:
  1530.         push ecx
  1531.         mov  ecx,10*4
  1532.         jmp short v16_virq
  1533. v16_virq9:
  1534.         push ecx
  1535.         mov  ecx,9*4
  1536.         jmp short v16_virq
  1537. v16_virq8:
  1538.         push ecx
  1539.         mov  ecx,8*4
  1540.         jmp short v16_virq
  1541. v16_virq7:
  1542.         push ecx
  1543.         mov  ecx,7*4
  1544.         jmp short v16_virq
  1545. v16_virq6:
  1546.         push ecx
  1547.         mov  ecx,6*4
  1548.         jmp short v16_virq
  1549. v16_virq5:
  1550.         push ecx
  1551.         mov  ecx,5*4
  1552.         jmp short v16_virq
  1553. v16_virq4:
  1554.         push ecx
  1555.         mov  ecx,4*4
  1556.         jmp short v16_virq
  1557. v16_virq3:
  1558.         push ecx
  1559.         mov  ecx,3*4
  1560.         jmp short v16_virq
  1561. v16_virq2:
  1562.         push ecx
  1563.         mov  ecx,2*4
  1564.         jmp short v16_virq
  1565. v16_virq1:
  1566.         push ecx
  1567.         mov  ecx,1*4
  1568.         jmp short v16_virq
  1569. v16_virq0:
  1570.         push ecx
  1571.         xor ecx,ecx
  1572. v16_virq:
  1573.         ; ecx = vector to call from protected mode
  1574.         pushad
  1575.         push ds
  1576.         push es
  1577.         push fs
  1578.         push gs
  1579.         mov ax,code32 ; now on shared data segment
  1580.         mov ds,ax     ;
  1581.         push s16_SavStackOfs      ; save on current stack
  1582.         push s16_SavStackSeg      ;
  1583.         mov ax,codeend
  1584.         mov s16_SavStackOfs,esp   ;
  1585.         mov s16_SavStackSeg,ss    ; save stack
  1586.         mov ss,ax              ;
  1587.         mov esp,nextmodestack  ; setup real mode stack on next stack frame
  1588.         ; the instruction
  1589.         ; sub nextmodestack,(STACKSWTP*16) ; new stack frame
  1590.         ; will be executed IN PROTECTED MODE
  1591.         ; AFTER stack reloading
  1592.  
  1593.         mov v16_sw_dest,offset v32_virqserver ; jump to p. mode virq server
  1594.         mov esi,v16_VCPIsys   ; system data for mode switch
  1595.         mov ax,0de0ch   ; SWITCH TO PROTECTED MODE thru VCPI
  1596.         int 67h         ;
  1597. v16_virqdone:
  1598.         ; ss:esp  set to values saved into s16_SavStackSeg:s16_SavStackOfs
  1599.         ; ds,es,fs,gs = code32
  1600.         pop s16_SavStackSeg
  1601.         pop s16_SavStackOfs
  1602.         add nextmodestack,(STACKSWTP*16) ; previous new stack frame
  1603.         pop gs
  1604.         pop fs
  1605.         pop es
  1606.         pop ds
  1607.         popad
  1608.         pop ecx
  1609.         iret
  1610.  
  1611. ;-----------------------------------------------------------------------------
  1612. ; XMS dos-extender
  1613. ;
  1614. x16_retreal:
  1615.         mov esi,code16
  1616.         mov edi,offset XMSExit
  1617.         jmp HARD_P2R
  1618.  
  1619. XMSExit:
  1620.         say msg_unlock
  1621.         mov dx,xms_handle
  1622.         mov ax,0D00h        ; unlock block
  1623.         call xms_entry
  1624. XMSMemExit:
  1625.         say msg_releasemem
  1626.         mov dx,xms_handle
  1627.         mov ax,0A00h        ; release block
  1628.         call xms_entry
  1629.         jmp exit
  1630.  
  1631. fail_a20:
  1632.         say em4_noA20
  1633.         jmp exit
  1634. fail_mem:
  1635.         say em3_no_himem
  1636.         jmp exit
  1637. fail_lock:
  1638.         say msg_badlock
  1639.         jmp exit
  1640.  
  1641. StartXMS:
  1642.         ; get XMS entry point
  1643.         say msg_XMSfound
  1644.         mov _386Man,IS_XMS
  1645.  
  1646.         mov _EXIT_SEL,20h                        ;
  1647.         mov _EXIT_ADDR,large offset x16_retreal  ; set program termination data
  1648.  
  1649.         mov ax,4310h
  1650.         int 2Fh
  1651.         mov word ptr xms_entry,bx
  1652.         mov word ptr ds:(2+ offset xms_entry),es
  1653.         ; check if A20 line is enabled
  1654.         mov ax,700h
  1655.         call xms_entry
  1656.         cmp ax,1
  1657.         je xms_a20_on
  1658.         ; enable A20 line
  1659.         mov ax,300h
  1660.         call xms_entry
  1661.         or ax,ax
  1662.         jz fail_a20
  1663. xms_a20_on:
  1664.         xor bx,bx
  1665.         ; how much ext mem ?
  1666.         mov ax,800h
  1667.         call xms_entry
  1668.         cmp ax,EXTMIN
  1669.         jb fail_mem
  1670.         mov word ptr _HiMemTop,ax
  1671.         ; try to allocate ext mem
  1672.         mov dx,ax
  1673.         mov ax,900h
  1674.         call xms_entry
  1675.         or ax,ax
  1676.         jz fail_mem
  1677.         mov xms_handle,dx
  1678.         ; try to lock block
  1679.         mov ax,0C00h
  1680.         or ax,ax
  1681.         jz fail_lock
  1682.         shl edx,16
  1683.         mov eax,_HiMemTop
  1684.         mov dx,bx
  1685.         shl eax,10 ; Kbytes --> Bytes
  1686.         mov _HiMemBase,edx
  1687.         add eax,edx
  1688.         mov _HiMemTop,eax
  1689.         ;
  1690.         ; Now, A20 line is enabled &  ext. mem is allocated and locked
  1691.         ; go on and initialize protected mode
  1692.         say msg_XMSjoin
  1693. JoinXMS: ; HARD init code will be the same of XMS from this point on
  1694.  
  1695.         ; modify code switchpoint
  1696.         mov s16_irToSYS32, offset irToHARD32
  1697.  
  1698.         ; AX = TOP INTERRUPT  NEEDED
  1699.         mov eax,77h ; we need to replace ints from 0 to 77h
  1700.         mov s16_Int_to_replace_ctr,ax  ; save number of ints to replace
  1701.         
  1702.         ; SET INT VECTOR TABLE
  1703.  
  1704.         lea eax,[eax*8+7]    ; set limit of IDT (every entry is 8 bytes)
  1705.         mov s16_IDTaddr,ax   ; (don't, worry we use the lower 16 bits)
  1706.  
  1707.         ; NOW ALLOCATE&INITIALIZE IDT
  1708.         say msg_idt
  1709. HARD_IDT:
  1710.         ; ALLOCATE SPACE FOR IDT
  1711.         call InitAlloc
  1712.         mov s32_idt32ptr,eax ; store pointer
  1713.         mov ebp,_Code32Base ;_Code32Base into ebp for immediate and later usage
  1714.         add eax,ebp         ; get linear address of IDT
  1715.         mov dword ptr bases16_IDTaddr,eax  ; set IDT base address
  1716.         
  1717. HARD_TSS_SETUP:
  1718.         say msg_tss
  1719.         mov eax,68h   ; TSS is 68h bytes wide
  1720.  
  1721.         call InitAlloc; allocate space for TSS
  1722.  
  1723.         add eax,ebp   ; get linear address of TSS
  1724.  
  1725.         ; set Task Switch Segment (TSS) descriptor base address
  1726.         or dword ptr baseGDTtask,eax
  1727.  
  1728.         mov ebx,eax
  1729.         shr eax,4
  1730.         mov es,ax
  1731.         and ebx,0Fh
  1732.         ;  es:bx = TSS start
  1733.  
  1734.         ; first of all, clear everything (i'm paranoid)
  1735.         mov di,bx    ; clear TSS and IO bitmap
  1736.         xor eax,eax  ;
  1737.         mov ecx,1Ah  ; TSS size in dwords
  1738.         rep stosd    ; T-bit is cleared into this loop
  1739.  
  1740.         ; then set IObitmap position, so the server will know there is not
  1741.         mov byte ptr es:[bx+66h],68h ; 68h == end of tss
  1742.  
  1743.         mov eax,CR3
  1744.         mov es:[bx+1Ch],eax ; set CR3 in TSS (i'm paranoid)
  1745.  
  1746.         say msg_HARDkick
  1747.         ; go protected
  1748.         mov esi,20h
  1749.         mov edi,large offset hard_protected16
  1750.         jmp HARD_R2P
  1751. hard_protected16:        ; in 16bit prot. mode
  1752.         ; Now set 32 bit protected mode segments and stack pointer
  1753.         cli
  1754.  
  1755.         ; gs= linear
  1756.         ;  ds,es,fs,ss = data32
  1757.         
  1758.         mov esp,(STACKSIZE*16)     ; esp set at stack start in 16bit mode
  1759.         add esp,Stack32BaseOffset  ; esp = prot. mode stack base
  1760.         
  1761.         ; now set up 32bit mode completely
  1762.  
  1763. HARD_ready32:
  1764.  
  1765.         ; now inizialize IDT with general exception handler
  1766.         mov edi,s32_idt32ptr ; get code32 relative ptr to IDT
  1767.         
  1768.         ; now EDI == base pointer to IDT
  1769.         
  1770.         ; set general exception handler
  1771.         ; into ALL SLOTS OF VCPI CLIENT INTERRUPT TABLE
  1772.         ; (default reaction to "unknown interrupt" is auto-reset)
  1773.         xor esi,esi ; clear esi
  1774.         mov si,s16_Int_to_replace_ctr
  1775.         
  1776.         mov eax,offset s32_exc  ; set the generic exception handler as default
  1777.         and eax,0000ffffh       ; offset s32_exc (we know it's under 64k)
  1778.         or  eax,00080000h       ; code32 pmode selector
  1779.         
  1780.         mov ebp,00008E00h       ; flags & higher (clear) offset
  1781.                                 
  1782.         ; IDT entry (8 bytes)
  1783.         ; offset  size
  1784.         ;      0     2   low offset  of ISR (Interrupt Service Routine)
  1785.         ;      2     2   selector    of ISR
  1786.         ;      4     2   flags
  1787.         ;      6     2   high offset of ISR
  1788.         
  1789. HX_IDTEntry:
  1790.         ; selector = 8
  1791.         ; offset    = offset s32_exc (generic handler)
  1792.         mov [edi+esi*8],eax ; offset basso e selettore
  1793.         mov [edi+esi*8+4],ebp ; flags & offset alto azzerato
  1794.         dec si
  1795.         jns HX_IDTEntry
  1796.         
  1797.         ; NOW IT'S TIME TO SET INTO THE INTERRUPT TABLE
  1798.         ; THE OFFSETS OF THE ISR ROUTINES WE SUPPORT
  1799.         ; copy exception handlers from IDT
  1800.         mov esi,16 ; 16 irq + 1 "DPMI api interrupt"
  1801.         xor ebx,ebx
  1802. HX_IDTInt:
  1803.         mov bl,intslotnum[si]
  1804.         mov eax,[esi*4+s16_idt_default] ; get ISR offset from s16_idt_default
  1805.         mov [edi+ebx*8],ax ; put into into the correct slot
  1806.         dec si
  1807.         jns HX_IDTInt
  1808.  
  1809.         jmp JoinDPMI
  1810.  
  1811. ;==============================================================================
  1812. ; 16 bit HARD/XMS redirectors
  1813.  
  1814. ; HARD/XMS real mode irq reflector to prot mode
  1815.  
  1816. s16_virqf:
  1817.         push ecx
  1818.         mov  ecx,15*4
  1819.         jmp s16_virq
  1820. s16_virqe:
  1821.         push ecx
  1822.         mov  ecx,14*4
  1823.         jmp s16_virq
  1824. s16_virqd:
  1825.         push ecx
  1826.         mov  ecx,13*4
  1827.         jmp short s16_virq
  1828. s16_virqc:
  1829.         push ecx
  1830.         mov  ecx,12*4
  1831.         jmp short s16_virq
  1832. s16_virqb:
  1833.         push ecx
  1834.         mov  ecx,11*4
  1835.         jmp short s16_virq
  1836. s16_virqa:
  1837.         push ecx
  1838.         mov  ecx,10*4
  1839.         jmp short s16_virq
  1840. s16_virq9:
  1841.         push ecx
  1842.         mov  ecx,9*4
  1843.         jmp short s16_virq
  1844. s16_virq8:
  1845.         push ecx
  1846.         mov  ecx,8*4
  1847.         jmp short s16_virq
  1848. s16_virq7:
  1849.         push ecx
  1850.         mov  ecx,7*4
  1851.         jmp short s16_virq
  1852. s16_virq6:
  1853.         push ecx
  1854.         mov  ecx,6*4
  1855.         jmp short s16_virq
  1856. s16_virq5:
  1857.         push ecx
  1858.         mov  ecx,5*4
  1859.         jmp short s16_virq
  1860. s16_virq4:
  1861.         push ecx
  1862.         mov  ecx,4*4
  1863.         jmp short s16_virq
  1864. s16_virq3:
  1865.         push ecx
  1866.         mov  ecx,3*4
  1867.         jmp short s16_virq
  1868. s16_virq2:
  1869.         push ecx
  1870.         mov  ecx,2*4
  1871.         jmp short s16_virq
  1872. s16_virq1:
  1873.         push ecx
  1874.         mov  ecx,1*4
  1875.         jmp short s16_virq
  1876. s16_virq0:
  1877.         push ecx
  1878.         xor ecx,ecx
  1879. s16_virq:
  1880.         ; ecx = vector to call from protected mode
  1881.         pushad
  1882.         push ds
  1883.         push es
  1884.         push fs
  1885.         push gs
  1886.         mov ax,code32 ; now on shared data segment
  1887.         mov ds,ax     ;
  1888.         push s16_SavStackOfs      ; save "old" stack on this stack
  1889.         push s16_SavStackSeg      ;
  1890.  
  1891.         mov ax,codeend
  1892.  
  1893.         mov s16_SavStackOfs,esp   ;
  1894.         mov s16_SavStackSeg,ss    ; save stack into global vars
  1895.         
  1896.         mov ss,ax
  1897.         mov esp,nextmodestack
  1898.         sub nextmodestack,(STACKSWTP*16)
  1899.         mov esi,08h ; _SelCode
  1900.         mov edi,offset s32_virqserver ; jump to p. mode virq server
  1901.         jmp HARD_R2P ; go real to protected mode
  1902.  
  1903. s16_virqdone:
  1904.         ; ss:esp  set to values saved into s16_SavStackSeg:s16_SavStackOfs
  1905.         ; ds,es,fs,gs = code32
  1906.         mov ss,s16_SavStackSeg   ; restore previous stack
  1907.         mov esp,s16_SavStackOfs  ;
  1908.         pop s16_SavStackSeg ; restore saved stack
  1909.         pop s16_SavStackOfs ;
  1910.         add nextmodestack,(STACKSWTP*16) ; back to last new stack frame
  1911.         pop gs
  1912.         pop fs
  1913.         pop es
  1914.         pop ds
  1915.         popad
  1916.         pop ecx
  1917.         iret
  1918.  
  1919. ;-----------------------------------------------------------------------------
  1920. ; HARD 386P init code
  1921.  
  1922. A20KBwait:  ; wait for safe to write to 8042
  1923.         xor cx,cx
  1924. KBsooloong:
  1925.         jmp short $+2 ;  waste so time to let 802 keep up
  1926.         jmp short $+2 ;
  1927.         jmp short $+2 ;
  1928.         in al,64h           ; read 8042 status
  1929.         test al,2           ; buffer full?
  1930.         loopnz  KBsooloong  ; if yes, loop
  1931.         ret
  1932.  
  1933. ;-----------------------------------------------------------------------------
  1934. A20test: ; test for enabled A20
  1935.         mov al,fs:[0]         ; get byte from 0:0
  1936.         mov ah,al             ; preserve old byte
  1937.         not al                ; modify byte
  1938.         xchg al,gs:[10h]      ; put modified byte to 0ffffh:10h
  1939.         cmp ah,fs:[0]         ; set zero if byte at 0:0 not modified
  1940.         mov gs:[10h],al       ; put back old byte at 0ffffh:10h
  1941.         ret                   ; return, zero if A20 enabled
  1942.  
  1943. s16_retreal:
  1944.         mov esi,code16
  1945.         mov edi,offset exit
  1946.         jmp HARD_P2R
  1947.  
  1948.  
  1949. StartHARD: ; Initialize protected mode
  1950.            ; on a system with just PC BIOS support.
  1951.            ; This means we will have to handle hardware directly
  1952.            ; and hope everything is pc compatible.
  1953.            ; Really HARD to run on raw HARDware. :)
  1954.         mov _386Man,IS_HARD
  1955.         mov _EXIT_SEL,20h                        ;
  1956.         mov _EXIT_ADDR,large offset s16_retreal  ; set program termination data
  1957.         ;---------------------------
  1958.         ; Set _HiMemTop
  1959.         ;
  1960.  
  1961.         mov ah,88h  ; how much extended memory free ?
  1962.         int 15h     ;
  1963.         ; this bios call sometimes has implementation bugs
  1964.         ; the docs says you can check the carry flag
  1965.         ; to see if it is successful, but no all BIOSes around
  1966.         ; set the carry flag correctly, so it better to hope for good and go..
  1967.         cmp ax,EXTMIN
  1968.         jb fail_mem
  1969.         ; this method allows access to max 64Mbytes of ram
  1970.         and eax,0FFFFh
  1971.         shl eax,10
  1972.         add eax,100000h   ; add one megabyte of ram
  1973.         mov _HiMemTop,eax
  1974.  
  1975.         ;-------------------------------------------------------------------
  1976.         ; NOW ENABLE a20 address line
  1977.  
  1978.         xor ax,ax                       ; set A20 test segments 0 and 0ffffh
  1979.         mov fs,ax
  1980.         dec ax  ; now ax = 0FFFFh
  1981.         mov gs,ax
  1982.  
  1983.         call A20test          ; is A20 already enabled?
  1984.         jz short a20done      ; if yes, done
  1985.  
  1986.         in al,92h                       ; PS/2 A20 enable
  1987.         or al,2
  1988.         jmp short $+2   ; wait a little ...
  1989.         jmp short $+2   ;
  1990.         jmp short $+2   ;
  1991.         out 92h,al
  1992.  
  1993.         call A20test        ; is A20 enabled?
  1994.         jz short a20done    ; if yes, done
  1995.  
  1996.         in al,65h       ; AT fast A20 enable
  1997.         or al,4
  1998.         jmp short $+2   ; wait a little ...
  1999.         jmp short $+2   ;
  2000.         jmp short $+2   ;
  2001.         out 65h,al
  2002.  
  2003.         call A20test        ; is A20 enabled?
  2004.         jz short a20done    ; if yes, done
  2005.  
  2006.         call A20KBwait            ; AT "keyboard controlled" A20 enable
  2007.         jnz short a20slowdone
  2008.  
  2009.         mov al,0d1h
  2010.         out 64h,al
  2011.  
  2012.         call A20KBwait
  2013.         jnz short a20slowdone
  2014.  
  2015.         mov al,0dfh
  2016.         out 60h,al
  2017.  
  2018.         call A20KBwait
  2019. a20slowdone:
  2020.                         ; wait for A20 to enable
  2021.         mov cx,0A00h    ; do A00h tries
  2022.  
  2023. a20slowloop:
  2024.         call A20test   ; is A20 enabled?
  2025.         jz a20done           ; if yes, done
  2026.  
  2027.         in al,40h      ; get current tick counter
  2028.         jmp short $+2
  2029.         jmp short $+2
  2030.         jmp short $+2
  2031.         in al,40h
  2032.         mov ah,al
  2033.  
  2034. same_tick:             ; wait a single tick
  2035.         in al,40h
  2036.         jmp short $+2
  2037.         jmp short $+2
  2038.         jmp short $+2
  2039.         in al,40h
  2040.         cmp al,ah
  2041.         je same_tick
  2042.  
  2043.         loop a20slowloop              ; loop for another try
  2044.         call A20test
  2045.         jz a20done
  2046.         jmp fail_a20
  2047.  
  2048. a20done:
  2049.         ;--------------------------------
  2050.         ; now set _HiMemBase
  2051.         ;
  2052.  
  2053.         xor dx,dx                       ; ES -> 0 (interrupt vector table)
  2054.         mov es,dx                       ;
  2055.         les bx,dword ptr es:[4*19h]     ; ES:BX -> int vector table
  2056.         ; now es:bx points to int 19h (reset) vector
  2057.  
  2058.         mov eax,100000h                 ; initial free extended memory base
  2059.  
  2060.         cmp dword ptr es:[bx+12h],'SIDV'; VDISK memory allocation?
  2061.         jne short go_check_ext_base ; no, free ext mem starts at first meg
  2062.         ; if VDISK present, get base of free ext mem
  2063.         ; AFTER vdisk data
  2064.         mov eax,es:[bx+2ch] ; get first free byte of extended mem
  2065.         add eax,0fh         ; align on paragraph
  2066.         and eax,0fffff0h    ; base address is only 24bit
  2067.  
  2068. go_check_ext_base:
  2069.         dec dx     ; ES -> 0ffffh for ext mem addressing
  2070.         mov es,dx  ;
  2071.         ; now try other VDISK presence method
  2072.  
  2073.         cmp dword ptr es:[13h],'SIDV'   ; VDISK memory allocation?
  2074.         jne short vdisk_done            ; if present, get base of free mem
  2075.         xor ebx,ebx      ;
  2076.         mov bx,es:[2eh]  ; get first free K of extended memory
  2077.         shl ebx,10       ; adjust K to bytes
  2078.  
  2079.         cmp eax,ebx         ; what's the higher one ?
  2080.         ja short vdisk_done
  2081.  
  2082.         mov eax,ebx
  2083.  
  2084. vdisk_done:
  2085.         mov _HiMemBase,eax
  2086.         mov edx,_HiMemTop
  2087.         sub edx,eax
  2088.         shr edx,10
  2089.         cmp edx,EXTMIN
  2090.         jb  fail_mem
  2091.  
  2092.         push ds
  2093.         mov ax,code16
  2094.         mov ds,ax
  2095.         mov dx,offset hardint15
  2096.         mov ax,2515h
  2097.         int 21h           ; patch int15
  2098.         pop ds
  2099.         jmp JoinXMS
  2100.  
  2101. dummypointer dd 0
  2102.  
  2103. hardint15:                         ; real mode INT 15h handler
  2104.         cmp ah,88h          ; function 88h?
  2105.         je short my15       ;
  2106.         push ds
  2107.         push eax
  2108.         mov ax,code32
  2109.         mov ds,ax
  2110.         mov eax,ds:[(15h*4)+ offset _OldInt] ; old INT 15h handler
  2111.         mov cs:dummypointer,eax
  2112.         pop eax
  2113.         pop ds
  2114.         jmp dword ptr cs:dummypointer
  2115.         
  2116. my15:
  2117.         xor ax,ax  ; zero k free
  2118.         iret ; return without modifying the carry flag
  2119.              ;  (to be consistent with the documentated bug ;) )
  2120.  
  2121.  
  2122. code16  ends
  2123.  
  2124. ; 32bit code
  2125. code32  segment para public use32
  2126.         assume cs:code32, ds:code32, ss:code32
  2127.  
  2128. ; THE "START" OF CODE32 MUST ALWAYS LOOK AS FOLLOWS HERE
  2129. ; TO LET "EXTERNAL" 386P DRIVERS HAVE FULL ACCESS TO THE 386P API CODE AND DATA
  2130. ; SO DON'T CHANGE
  2131. ; HOW THE SUBSEQUENT DECLARATIONS ARE ALIGNED, ORDERED AND DECLARED!!!!!
  2132.  
  2133. ; N.B. this "fixed table" is useful to access virtual registers
  2134. ;      and the memory allocation vars. But,please don't abuse of it.
  2135.  
  2136. ; 32 bit common system data
  2137.                 align dword
  2138.                 dd      0               ; scratch dword 
  2139. _LoMemBase      dd      0               ; low mem base for allocation
  2140. _LoMemTop       dd      0               ; top of low mem
  2141.  
  2142. _HiMemBase      dd      0               ; high mem base for allocation
  2143. _HiMemTop       dd      0               ; top of high mem
  2144.  
  2145. _PSPBase        dd      0               ; LINEAR offset of start of PSP 
  2146. _Code16Base     dd      0               ; LINEAR offset of start of 16bit code 
  2147. _Code32Base     dd      0               ; LINEAR offset of start of 32bit code
  2148.  
  2149.                 align byte
  2150.                 ; (byte alignment, but we know we will have optimal alignment)
  2151. ; Virtual 8086 Registers
  2152. V86edi        label   dword      ; vregs for 386P<-->V86 communication
  2153. V86di         dw      0, 0       ; we need this order if we want
  2154. V86esi        label   dword      ; to bypass 386POWER and go thru DPMI API
  2155. V86si         dw      0, 0       
  2156. V86ebp        label   dword      
  2157. V86bp         dw      0, 0       
  2158.               dd      0          ; this DWORD is a 'fake' esp (see POPAD)
  2159. V86ebx        label   dword
  2160. V86bx         label   word
  2161. V86bl         db      0
  2162. V86bh         db      0, 0,0
  2163. V86edx        label   dword
  2164. V86dx         label   word
  2165. V86dl         db      0
  2166. V86dh         db      0, 0,0
  2167. V86ecx        label   dword
  2168. V86cx         label   word
  2169. V86cl         db      0
  2170. V86ch         db      0, 0,0
  2171. V86eax        label   dword
  2172. V86ax         label   word
  2173. V86al         db      0
  2174. V86ah         db      0, 0,0
  2175. V86F          dw      0
  2176. V86es         dw      0
  2177. V86ds         dw      0
  2178. V86fs         dw      0
  2179. V86gs         dw      0
  2180. tempaddr      dd      0 ; dummy CS:IP or EIP to call when irq-ing to/from pmode
  2181. tempstack     dd      0 ; dummy SS:SP (DPMI will set up a 30 word stack)
  2182.               dw      0 ; plus a word to keep things aligned at 32bit
  2183.                 
  2184. ; integrated irq management support
  2185. _GetIRQ     dd      s32_getirq       ; get IRQ handler offset routine addr
  2186. _SetIRQ     dd      s32_setirq       ; set IRQ handler offset routine addr
  2187. _GetIMask   dd      _GetIRQMask
  2188. _SetIMask   dd      _SetIRQMask
  2189.  
  2190.  
  2191.                 align word
  2192. _SelCode        dw      08h     ; code32 segment selector
  2193. _SelData        dw      10h     ; data segment alias for code32
  2194. _SelZero        dw      18h     ; data segment starting at addressing base
  2195.                 dw      0 ; unused word, to align things
  2196.  
  2197. ; ptr to termination message
  2198.                 public _386Return
  2199. _386Return      dd offset _386Terminator
  2200.                 align byte
  2201. _CPUPower       db      0             ; cpu type: (NO INFO ABOUT FPU!!!!!!)
  2202.                                       ; 0 = 8086
  2203.                                       ; 1 = 80186
  2204.                                       ; 2 = 286
  2205.                                       ; 3 = 386
  2206.                                       ; 4 = 486
  2207.                                       ; 5 = Pentium
  2208.  
  2209. _386Man         db      0             ; 386 manager
  2210.                                       ; 0=VCPI, 1=DPMI
  2211.                 dw      0    ; reserved
  2212.  
  2213. ; basic dos-extender services
  2214. _ExecINT        dd    offset v32_ExecINT    ; executes an ms-dos INT call
  2215. _ExecReal       dd    offset v32_ExecReal   ; executes a real-mode FAR routine
  2216.         public _ExecINT,_ExecReal
  2217. ; integrated dma services
  2218. _DMAInfo        dd   offset VDMACheck    ; get info on dma resources
  2219. _DMAInit        dd   offset VDMAInit     ; initialize DMA services
  2220. ; hook to virtual dma services or emulate 'em
  2221. _DMALock        dd   offset DChanLock      ; lock dma channel
  2222. _DMAUnLock      dd   offset DChanUnLock    ; unlock dma channel
  2223. _DMASend        dd   offset VDMASend    ; send data thru dma
  2224. _DMAReceive     dd   offset VDMAReceive  ; receive data thru dma
  2225. _DMAMap         dd   offset DScatLock    ; map&lock scatter/gather memory
  2226. _DMAUnMap       dd   offset DScatUnLock  ; unmap&unlock scatter/gather memory
  2227.         public _DMAInfo,_DMAInit,_DMALock,_DMAUnLock
  2228.         public _DMASend,_DMAReceive,_DMAMap,_DMAUnMap
  2229.  
  2230. ; "STANDARD"  DRIVER_TO_386POWER INTERFACE TABLE ENDS HERE
  2231.  
  2232.  
  2233. ; standard termination text
  2234.                 public _386Terminator                        
  2235. _386Terminator  db '386Power 2.00 extended environment',CR,LF,'$'
  2236.  
  2237. public  V86eax, V86ebx, V86ecx, V86edx, V86esi, V86edi, V86ebp
  2238. public  V86ax, V86bx, V86cx, V86dx, V86si, V86di, V86bp
  2239. public  V86al, V86ah, V86bl, V86bh, V86cl, V86ch, V86dl, V86dh
  2240. public  V86ds, V86es, V86fs, V86gs
  2241. public  _SelCode, _SelData, _SelZero, _LoMemBase, _LoMemTop, _HiMemBase
  2242. public  _HiMemTop, _PSPBase, _Code16Base, _Code32Base, _GetIRQ, _SetIRQ
  2243. public  _386Man,_CPUPower
  2244.  
  2245. extrn   _Main:near
  2246.  
  2247. ;------------------------------------------------------------------------------
  2248. ; 16 bit common system data
  2249. ;------------------------------------------------------------------------------
  2250. ; debug messages  THESE MUST BE 16bit-accessible
  2251. msg_DPMItest  db 'Checking DPMI',CR,LF,'$'
  2252. msg_VCPItest  db 'Checking VCPI',CR,LF,'$'
  2253. msg_XMStest   db 'Checking XMS',CR,LF,'$'
  2254. msg_HARDtest  db 'Support software not detected, trying to run directly',CR,LF
  2255.               db 'using native bios and hardware [HARDware mode]',CR,LF,'$'
  2256. msg_gints     db 'Saving DOS interrupt table',CR,LF,'$'
  2257. msg_pints     db 'Restoring IDT to default values',CR,LF,'$'
  2258. msg_rints     db 'Restoring DOS interrupt table',CR,LF,'$'
  2259. msg_end       db 'Terminating program ... CIAO! See you later.',CR,LF,'$'
  2260. msg_DPMIlar    db 'Checking access rights allowed by the DPMI server',CR,LF,'$'
  2261. msg_DPMIbadlar db 'LAR instruction failed, CPL set to default RING 3',CR,LF,'$'
  2262. msg_DPMInominfo db 'DPMI does not respond to memory info request',CR,LF,'$'
  2263. msg_DPMIhiget   db 'Checking if extended memory has to be allocated',CR,LF,'$'
  2264. msg_allocmem  db 'Allocating all available memory, please wait ...',CR,LF,'$'
  2265. msg_lockmem   db 'Locking extended memory ...',CR,LF,'$'
  2266. msg_badlock   db 'FAILED LOCKING EXTENDED MEMORY!',CR,LF,'$'
  2267. msg_DPMIwin   db 'Extended memory allocated',CR,LF,'$'
  2268. msg_DPMIirq   db 'Setting new DPMI irq handlers',CR,LF,'$'
  2269. msg_VCPIfree  db 'Freeing pages allocated thru VCPI',CR,LF,'$'
  2270. msg_DPMIifail db 'DPMI prot. mode irq allocation failure',CR,LF,'$'
  2271. msg_DPMIgood  db 'DPMI initialization completed',CR,LF,'$'
  2272. msg_VCPIkick  db 'Ready to enter VCPI protected mode',CR,LF,'$'
  2273. msg_XMSfound  db 'Detected XMS interface',CR,LF,'$'
  2274. msg_XMSjoin   db 'XMS/HARD common initialization ...',CR,LF,'$'
  2275. msg_HARDkick  db 'Ready to enter HARD protected mode',CR,LF,'$'
  2276. msg_DPMIcode32 db 'Setting 32bit code   selector',CR,LF,'$'
  2277. msg_DPMIdata32 db 'Setting 32bit data   selector',CR,LF,'$'
  2278. msg_DPMIzero32 db 'Setting 32bit linear selector',CR,LF,'$'
  2279. msg_unlock      db 'Unlocking extended memory',CR,LF,'$'
  2280. msg_releasemem  db 'Freeing extended memory',CR,LF,'$'
  2281. msg_DPMIrcode32 db 'Releasing 32bit code   selector',CR,LF,'$'
  2282. msg_DPMIrdata32 db 'Releasing 32bit data   selector',CR,LF,'$'
  2283. msg_DPMIrzero32 db 'Releasing 32bit linear selector',CR,LF,'$'
  2284. msg_DPMIfinal   db 'Final DPMI call for total shutdown',CR,LF,'$'
  2285.  
  2286. msg_DPMI_SR_FAIL db 'DPMI ERROR: SAVE/RESTORE STATE FAILURE',CR,LF,'$'
  2287. msg_DPMI_MS_FAIL db 'DPMI ERROR: MODE SWITCH FAILURE',CR,LF,'$'
  2288. msg_DPMI_IV_FAIL db 'DPMI ERROR: INTERRUPT CONTROLLER ACCESS FAILURE',CR,LF,'$'
  2289. msg_DPMI_GI_FAIL db 'DPMI ERROR: GET IRQ FAILURE',CR,LF,'$'
  2290. msg_DPMI_SI_FAIL db 'DPMI ERROR: SET IRQ FAILURE',CR,LF,'$'
  2291.  
  2292. msg_VCPIpic  db 'Looking for P.I.C. vector mapping',CR,LF,'$'
  2293. msg_idt  db 'Allocating IDT (will be set while into prot. mode)',CR,LF,'$'
  2294. msg_tss  db 'Allocating and setting TSS ',CR,LF,'$'
  2295. msg_paging  db 'Allocating and setting page tables ',CR,LF,'$'
  2296. msg_VCPIhookserver  db 'Interfacing with VCPI server',CR,LF,'$'
  2297. msg_VCPIaddpages    db 'Adding extended memory to page table',CR,LF,'$'
  2298. msg_VCPIpagedir     db 'Initializing page directory',CR,LF,'$'
  2299. msg_going_main db ' ENTERED FULL 32BIT MODE, ready for main program start',CR,LF,'$'
  2300.  
  2301.         
  2302.  
  2303. ; hex ->ascii translation table
  2304. emT_hextable db '0123456789ABCDEF'
  2305.  
  2306. ; standard message             
  2307. emX_stderr   db '[ See file 386ERROR.TXT for more info ]',7,CR,LF,'$'
  2308.  
  2309. ; error strings %%%
  2310. em0_86  db 'Error 00: 386 COMPATIBLE PROCESSOR NOT DETECTED!',CR,LF
  2311.         db 'Found an 8086 cpu',CR,LF,'$'
  2312. em0_286 db 'Error 00: 386 COMPATIBLE PROCESSOR NOT DETECTED!',CR,LF
  2313.         db 'Found a 80286 cpu',CR,LF,'$'
  2314. em1_no_lomem   db 'Error 01: NOT ENOUGH MEMORY UNDER 640KB!',CR,LF,'$'
  2315. emINI_no_lomem db 'Error 01: NOT ENOUGH MEMORY UNDER 640KB!',CR,LF
  2316.                db '  (While allocating internal structures)',CR,LF,CR,LF,'$'
  2317.  
  2318. em2_unkV86 db CR,LF,'Error 02: UNKNOWN MEMORY MANAGER DRIVES V86 MODE!',CR,LF
  2319.            db CR,LF,'          DPMI or VCPI server NOT detected.',CR,LF
  2320.            db CR,LF,'          Detected an unknown V86 memory manager '
  2321.            db CR,LF,'          maybe you are running old system software.'
  2322.            db CR,LF,CR,LF,'$'
  2323.  
  2324. em3_no_himem db 'Error 03: NOT ENOUGHT MEMORY ABOVE 1MB!',CR,LF,'$'
  2325. em4_noA20    db 'Error 04: A20 ADDRESS LINE NOT ENABLED!',CR,LF,'$'
  2326. em5_hifault  db 'Error 05: FAILED ALLOCATION OF MEMORY ABOVE 1MB!',CR,LF,'$'
  2327. em6_PICfault db 'Error 06: VCPI P.I.C. INT MAPPED ON 386POWER INTS',CR,LF,'$'
  2328. em7_noDPMI32 db 'Error 07: NOT A 32 BIT DPMI HOST!',CR,LF,'$'
  2329. em8_DPMIdesc db 'Error 08: NOT ENOUGH DPMI DESCRIPTORS!',CR,LF,'$'
  2330. em9_DPMImod  db 'Error 09: CANNOT MODIFY DPMI DESCRIPTORS!',CR,LF,'$'
  2331. emA_FIX      db 'Error 0A: VCPI HAS NOT ENOUGH PAGES AVAILABLE!',CR,LF,'$'
  2332. emB_lowDPMI  db 'Error 0B: DPMI API IS OLDER THAN DPMI 0.9',CR,LF,'$'
  2333. emC_linear   db 'Error 0C: LINEAR MEMORY SPACE EXAUSTED',CR,LF,'$'
  2334. emD_phys     db 'Error 0D: PHYSICAL MEMORY SPACE EXAUSTED',CR,LF,'$'
  2335. emE_backing  db 'Error 0E: BACKING STORAGE EXAUSTED',CR,LF,'$'
  2336. emF_handle   db 'Error 0F: INVALID HANDLE',CR,LF,'$'
  2337. em10_invalid db 'Error 10: INVALID PARAMETER VALUE',CR,LF,'$'
  2338. em11_EqPIC   db 'Error 11: P.I.C. MAP ON SAME INTERRUPT SLOT',CR,LF,'$'
  2339.  
  2340. _386power_info db CR,LF
  2341.   db '┌────────────────────────────────────────────────────────────┐',CR,LF
  2342.   db '│  386Power Dos-Extender     386P Revision 2.000             │',CR,LF
  2343.   db '│                                                            │',CR,LF
  2344.   db '│     This is a public domain dos-extender module            │',CR,LF  
  2345.   db '│     designed for a VCPI/DPMI interface to protected mode.  │',CR,LF  
  2346.   db '│     You need a VCPI or DPMI manager to run this.           │',CR,LF
  2347.   db '│                                                            │',CR,LF    
  2348.   db '│     (c) Copyright Lorenzo Micheletto MCHLNZ67T19C890A      │',CR,LF
  2349.   db '│     All rights reserved, except the portions of 386Power   │',CR,LF
  2350.   db '│     based on the source code of the PMODE dos-extender     │',CR,LF  
  2351.   db '│     by Thomas "Tran" Pytel.                                │',CR,LF  
  2352.   db '│     See the 386Power documentation for explanations.       │',CR,LF  
  2353.   db '│                                                            │',CR,LF      
  2354.   db '└────────────────────────────────────────────────────────────┘',CR,LF  
  2355.   db CR,LF,'$'
  2356.  
  2357. wow_386 db CR,LF,'*******  386DX OR 386SX   PROCESSOR DETECTED  *******',CR,LF,CR,LF,'$'
  2358. wow_486 db CR,LF,'*******  486DX OR 486SX   PROCESSOR DETECTED  *******',CR,LF,CR,LF,'$'
  2359. wow_586 db CR,LF,'*******  PENTIUM OR 586   PROCESSOR DETECTED  *******',CR,LF,CR,LF,'$'
  2360. wow_cpu db CR,LF,'*******  686 OR SUPERIOR  PROCESSOR DETECTED  *******',CR,LF,CR,LF,'$'
  2361.  
  2362. msg_cputype  dd offset em0_86,   offset em0_86, offset em0_286
  2363.              dd offset wow_386, offset wow_486, offset wow_586
  2364.              dd offset wow_cpu, offset wow_cpu, offset wow_cpu
  2365.              dd offset wow_cpu, offset wow_cpu, offset wow_cpu
  2366.              dd offset wow_cpu, offset wow_cpu, offset wow_cpu
  2367.              dd offset wow_cpu
  2368. nullint      db   0cfh            ; IRET instruction
  2369. exitrout     dw   exit            ; exit routine, modified if VCPI
  2370.  
  2371. ;=============================================================================
  2372. ; 16 bit DPMI system data
  2373.  
  2374.                   align dword
  2375. d16_Fast16_To_32          dd      0  ; switch from 16bit to 32bit
  2376. d16_SaveRestoreState      dd      0  ; save/restore state addr
  2377.  
  2378. hidpmi_handle dd 0 ; dpmi memory manager handle of allocate high memory block
  2379. hidpmi_size   dd 0 ; size and linear address base of high memory
  2380. hidpmi_base   dd 0 ; locked by dpmi
  2381.                   align word
  2382. d16_EnterDPMI     dw      0,0 ; DPMI switch to protected mode (16bit)
  2383.  
  2384. d16_PSPSel        dw      0   ; PSP selector (use it in prot. mode)
  2385. d16_DosEnvSegSel  dw      0   ; ENVIRONMENT selector
  2386.  
  2387.             align dword
  2388. d16_nintoff dd offset d32_irq0,offset d32_irq1,offset d32_irq2
  2389.             dd offset d32_irq3,offset d32_irq4,offset d32_irq5
  2390.             dd offset d32_irq6,offset d32_irq7
  2391.             dd offset d32_irq8,offset d32_irq9,offset d32_irqa
  2392.             dd offset d32_irqb,offset d32_irqc,offset d32_irqd
  2393.             dd offset d32_irqe,offset d32_irqf
  2394.  
  2395.             
  2396. ;-----------------------------------------------------------------------------
  2397. ; 16bit VCPI system data
  2398.  
  2399. ; VCPI EMS DATA
  2400.  
  2401. ; VCPI PAGE DIRECTORY DATA
  2402.                   align word
  2403. v16_PageDirSeg    dw      0             ; seg of page directory
  2404. v16_PageBase      dw      0             ; first page of himem (*4)+1000h
  2405. v16_PageTop       dw      0             ; top page of himem (*4)+1000h
  2406.                   dw      0A0Bh
  2407. ;------------------------------------------------------------------------------
  2408.                   align word
  2409.                   ; VCPI mode-switch data
  2410.                   ; after initialization this table may be copied
  2411.                   ; by the IRQ redirectors
  2412. v16_sw_cr3        dd      0                    ; new CR3 for 386P (physical)
  2413. v16_sw_gdtaddrptr dd      offset s16_GDTaddr   ; lin. ptr to GDT data for 386P
  2414. v16_sw_idtaddrptr dd      offset s16_IDTaddr ; lin. ptr to IDT data for 386P
  2415. v16_sw_ldtsel     dw      0      ; don't need LDTs, zero selector
  2416. v16_sw_trsel      dw      30h    ; task state segment (TSS) selector
  2417. v16_sw_dest       dd      0      ; switch destination EIP
  2418.                   dw      20h    ; switch destination CS (code16)
  2419.                   dw      0
  2420.  
  2421. v16_VCPIsys       dd offset v16_sw_cr3
  2422.  
  2423. ;----------------------------------------------------------------------------
  2424. ; 16 bit VCPI/XMS/HARD mode system data
  2425.  
  2426.                          align word
  2427.  
  2428. switchstackaddr          dd  0  ; SS:SP to pass during real mode switches
  2429.  
  2430. s16_Int_to_replace_ctr   dw  0  ; number of int vects needed -1
  2431.  
  2432. ; switchpoint to return to protected mode after int33, int32 from prot. mode.
  2433. s16_irToSYS32   dw offset irToVCPI32
  2434.  
  2435. s16_SavStackOfs dd 0   ; current saved stack offset  during real mode irq rfx
  2436. s16_SavStackSeg dw 0,0 ; current saved stack segment during real mode irq rfx
  2437.  
  2438. s16_IDTaddr     dw 0      ; limit must be set by VCPI/XMS/HARD init code
  2439. bases16_IDTaddr dd 0      ; 32bit IDT address
  2440.  
  2441. s16_GDTaddr       dw 04fh        ; limit for selectors 00h .. 48h
  2442. bases16_GDTaddr   dd offset GDT  ; 32bit GDT address
  2443.  
  2444. s16_IDT86       dw 3FFh   ; REAL MODE IDT (set to INT table)
  2445.                 dd 0      ;
  2446.  
  2447.                   align dword
  2448. s16_idt_default   dd   offset s32_irq0,offset s32_irq1,offset s32_irq2
  2449.                   dd   offset s32_irq3,offset s32_irq4,offset s32_irq5
  2450.                   dd   offset s32_irq6,offset s32_irq7,offset s32_irq8
  2451.                   dd   offset s32_irq9,offset s32_irqa,offset s32_irqb
  2452.                   dd   offset s32_irqc,offset s32_irqd,offset s32_irqe
  2453.                   dd   offset s32_irqf
  2454.                   dd   offset s32_int31
  2455. v16_idt_default   dd   offset v32_irq0,offset v32_irq1,offset v32_irq2
  2456.                   dd   offset v32_irq3,offset v32_irq4,offset v32_irq5
  2457.                   dd   offset v32_irq6,offset v32_irq7,offset v32_irq8
  2458.                   dd   offset v32_irq9,offset v32_irqa,offset v32_irqb
  2459.                   dd   offset v32_irqc,offset v32_irqd,offset v32_irqe
  2460.                   dd   offset v32_irqf
  2461.                   dd   offset s32_int31
  2462.                   ; int 31h is the same for vcpi and xms/hard
  2463.  
  2464.                 align dword
  2465.                 dd 0   ;scratch dword
  2466.                 align byte
  2467. ; Global Descriptors Table
  2468. GDT           dq      0                 ; 00h null selector, first into GDT
  2469. GDTcode32     dw      0ffffh
  2470. baseGDTcode32 db      0,0,0,9ah,0cfh,0  ; 08h code32 as 32bit code seg sel
  2471. GDTdata32     dw      0ffffh
  2472. baseGDTdata32 db      0,0,0,92h,0cfh,0  ; 10h code32 as 32bit data seg sel
  2473. GDTzero32     dw      0ffffh
  2474.               db      0,0,0,92h,0cfh,0  ; 18h 32bit LINEAR SPACE data seg sel
  2475. GDTcode16     dw      0ffffh
  2476. baseGDTcode16 db      0,0,0,9ah,0,0     ; 20h code16 as 16bit code seg sel
  2477. GDTdata16     dw      0ffffh
  2478. baseGDTdata16 db      0,0,0,92h,0,0     ; 28h code16 as 16bit data seg sel
  2479. GDTtask       dw      0067h ; TSS limit without i/o bitmap
  2480. baseGDTtask   db      0,0,0,89h,0,0     ; 30h TSS code seg sel
  2481. GDTvcpi       dq      3 dup(0)          ; 38h,40h,48h
  2482.      ;  il selettore 38h e' quello usato dal codice di inizializzazione VCPI
  2483.      ;  il selettore 40h e 48h e' per uso "interno" da parte di VCPI
  2484.  
  2485.         ; table containing interrupt vectors as found at 386P initialization          
  2486.         align dword
  2487. _OldInt dd 256 dup(0)
  2488.         public _OldInt
  2489. ;------------------------------------------------------------------------------
  2490. ; continue with 32bit data
  2491. ;------------------------------------------------------------------------------
  2492.  
  2493. public  _Exit, _GetMem, _GetLoMem, _GetHiMem
  2494. public  _GetIRQMask, _SetIRQMask
  2495.               
  2496.                 align byte
  2497. ; these are the 386power API & exception handler vector numbers
  2498. ; they must be consistent with the vectors into the XXX_idt_default tables
  2499. intslotnum      db      08h,09h,0Ah,0Bh,0Ch,0Dh,0Eh,0Fh
  2500.                 db      70h,71h,72h,73h,74h,75h,76h,77h
  2501.                         ; 16 int vectors for the two PICs
  2502.                         ; (VCPI and DPMI servers will rewrite 'em)
  2503.                 db      31h       ; the extra int to add to VCPI
  2504.  
  2505.                 align word
  2506.                 
  2507. _EXIT_ADDR      dd      offset v32_retreal ; offset of exit function
  2508. _EXIT_SEL       dw      08h,0              ; offset of exit function
  2509.                                            ; (defaults are VCPI values)
  2510.  
  2511. _EXIT_DATA_SEL  dw      10h          ; 32bit data code32 selector
  2512. _EXIT_SS        dw      0            ; set by DPMI code
  2513. _EXIT_ESP       dd      (STACKSIZE-(STACKUSER/2))*16
  2514.                                      ; if we are gonna terminate
  2515.                                      ; we can trash as much we want
  2516.                                      ; but it is better to avoid problems
  2517.  
  2518. OldIRQMask      dw      0            ; old port 21h and 0a1h masks
  2519.                  align dword
  2520.                  
  2521. OldBreakISR      dd      0               ; old int 1Bh  (ctrl+break)
  2522.  
  2523. nextmodestack    dd      (STACKSIZE-STACKUSER)*16 ; stack for next mode switch                 
  2524. Stack32BaseOffset dd      0    ; linear ptr to beginning of codeend
  2525.                               ; stack segment
  2526.                       align byte
  2527. d32_Fast32_To_16      df      0               ; switch from 32 to 16
  2528. d32_SaveRestoreState  df      0               ; save/restore state addr
  2529. d32_StateBufferSize   dd      0               ; length of state buffer
  2530.  
  2531.                       ; 16 IRQ ints
  2532. d32_OldInts           dq      16 dup(0)       ; saved interrupt addr buffer
  2533.                                               ; in dword aligned form
  2534. ;----------------------------------------------------------------------------                  
  2535. ; 32 bit VCPI system data
  2536.  
  2537. v32_vcpientryaddr df      3800000000h    ; VCPI entry point in 386P
  2538.                   ; n.b. this "in bytes" is stored as 00,00,00,00,38h,00
  2539.  
  2540. ;----------------------------------------------------------------------------
  2541. ; XMS data
  2542.  
  2543. xms_entry  dd 0
  2544. xms_handle dw 0
  2545.  
  2546. ;----------------------------------------------------------------------------
  2547. ; 32bit HARD/XMS system data
  2548.  
  2549. s32_switchentryaddr dd large offset HARD_P2R  ;  fword ptr to hard/xms
  2550.                     dw 20h                    ;  switchpoint
  2551.  
  2552. ;----------------------------------------------------------------------------
  2553. ; 32 bit custom system data
  2554.  
  2555.                  align dword
  2556.  
  2557. s32_idt32ptr     dd      0               ; ptr to 32bit IDT
  2558.  
  2559. s32_SavStackOfs  dd      0               ; current saved stack offset
  2560. s32_SavStackSel  dw      0,0             ; current saved stack selector
  2561.  
  2562. ; interrupt table needed for irq reflection from real mode
  2563. ; this stores 32bit far pointers (fword) aligned into qword boundaries
  2564. ; and because it is used only by VCPI/XMS/HARD, segment selector is 08h
  2565. s32_irqtable      dd   offset s32_irq0,8,offset s32_irq1,8,offset s32_irq2,8
  2566.                   dd   offset s32_irq3,8,offset s32_irq4,8,offset s32_irq5,8
  2567.                   dd   offset s32_irq6,8,offset s32_irq7,8,offset s32_irq8,8
  2568.                   dd   offset s32_irq9,8,offset s32_irqa,8,offset s32_irqb,8
  2569.                   dd   offset s32_irqc,8,offset s32_irqd,8,offset s32_irqe,8
  2570.                   dd   offset s32_irqf,8
  2571.                   dd   0,0 ,0,0 ,0,0    ; DUMMY ENTRIES TO AVOID
  2572.                                        ; OVERWRITES WHILE SETTING THE irqtable
  2573.                                        ; IN THE SET_IDT LOOP
  2574.  
  2575.         ;  pointer to the 32bit entry point for program start
  2576. Kick32  dd offset INIT_386P,0 ; higher word will be set with
  2577.                               ; the 32bit code selector at runtime
  2578.         align byte            
  2579. INIT_386P: ; common 32bit startup
  2580.  
  2581.         ; disable ctrl+break
  2582.         mov eax,gs:[1bh*4]      ; SAVE ctrl+break value, then crtl+break OFF
  2583.         mov OldBreakISR,eax     ;
  2584.  
  2585.         ;db 65h,67h,0c7h,6       ; MOV DWORD PTR GS:[1bh*4],code32:nullint
  2586.         ;dw 1bh*4,nullint,code32 ;
  2587.         ; this is the equivalent code in a "wider" form
  2588.         mov word ptr GS:[(1Bh)*4],offset nullint
  2589.         mov word ptr GS:[(1Bh*4)+2],code32
  2590.         
  2591.         in al,21h                       ; save old PIC masks
  2592.         mov ah,al                       ;
  2593.         jc ukka
  2594. ukka:   jnc akka
  2595. akka:   jc ekka
  2596. ekka:   jnc okka
  2597. okka:
  2598.         in al,0a1h                      ;
  2599.         mov OldIRQMask,ax               ;
  2600.  
  2601.         mov V86dx, small offset msg_going_main
  2602.         mov V86ds,code32
  2603.         mov V86ah,09
  2604.         mov al,21h
  2605.         call _ExecINT
  2606.  
  2607.         jmp _Main                       ; go to main code
  2608.  
  2609. ; protected mode position where HARD_R2P goes
  2610. ; before going to the final prot. mode destination
  2611. HARDPROT:
  2612.         cld        ; 386P default increment direction
  2613.         add esp,Stack32BaseOffset       ; set prot mode esp
  2614.         push esi                        ; store protected mode target CS
  2615.         push edi                        ; store protected mode target EIP
  2616.         retf                            ; go to protected mode destination
  2617.  
  2618.  
  2619.  
  2620. ; 386POWER API routines (very similar to pmode routines)
  2621.  
  2622. ; Allocate memory (first try low, then high)
  2623. ; In:
  2624. ;   EAX = size requested
  2625. ; Out:
  2626. ;   CF CLEAR = memory allocated
  2627. ;   CF SET   = not enough mem
  2628. ;   EAX = linear pointer to mem or ?
  2629. _GetMem:
  2630.         push eax
  2631.         call _GetLoMem
  2632.         jnc short getmemd
  2633.         pop eax
  2634.         jmp short _GetHiMem
  2635. getmemd:
  2636.         add esp,4
  2637.         ret
  2638.         
  2639. ; Allocate some low mem
  2640. ; In:
  2641. ;   EAX = size requested
  2642. ; Out:
  2643. ;   CF CLEAR = memory allocated
  2644. ;   CF SET   = not enough mem
  2645. ;   EAX = linear pointer to mem or ?
  2646. _GetLoMem:
  2647.         add eax,_LoMemBase
  2648.         cmp eax,_LoMemTop
  2649.         jnbe short getmemerr
  2650.         xchg eax,_LoMemBase
  2651.         clc
  2652.         ret
  2653. getmemerr:
  2654.         stc
  2655.         ret
  2656.         
  2657. ; Allocate some high mem
  2658. ; In:
  2659. ;   EAX = size requested
  2660. ; Out:
  2661. ;   CF CLEAR = memory allocated
  2662. ;   CF SET   = not enough mem
  2663. ;   EAX = linear pointer to mem or ?
  2664. _GetHiMem:
  2665.         add eax,_HiMemBase
  2666.         cmp eax,_HiMemTop
  2667.         jnbe short getmemerr
  2668.         xchg eax,_HiMemBase
  2669.         clc
  2670.         ret
  2671.         
  2672. ; Get status of IRQ mask bit
  2673. ; In:
  2674. ;   BL = IRQ num (0-15)
  2675. ; Out:
  2676. ;   AL = status: 0=enabled, 1=disabled
  2677. _GetIRQMask:
  2678.         push ax
  2679.         in al,0a1h ; get IRQ mask
  2680.         mov ah,al  ;
  2681.         in al,21h  ;
  2682.         xchg cl,bl ;
  2683.         shr ax,cl    ; shift bit to bit0
  2684.         xchg cl,bl
  2685.         and al,1     ; mask out other bits
  2686.         pop ax
  2687.         ret
  2688.         
  2689. ; Set status of IRQ mask bit
  2690. ; In:
  2691. ;   BL = IRQ num (0-15)
  2692. ;   AL = status: 0=enabled, 1=disabled
  2693. _SetIRQMask:
  2694.         push ax bx cx dx
  2695.         mov cl,bl
  2696.         mov bx,0fffeh
  2697.         movzx dx,al
  2698.         rol bx,cl
  2699.         shl dx,cl
  2700.         in al,0a1h
  2701.         mov ah,al
  2702.         in al,21h
  2703.         and ax,bx
  2704.         or ax,dx
  2705.         out 21h,al
  2706.         mov al,ah
  2707.         out 0a1h,al
  2708.         pop dx cx bx ax
  2709.         ret
  2710.         
  2711. ;------------------------------------------------------------------------------        
  2712. ; Exit to real mode
  2713.  
  2714. MAXX_EX=32
  2715.  
  2716. excount db 0
  2717.  
  2718.         align dword
  2719. ex_list dd MAXX_EX dup(0)
  2720.         align byte
  2721.  
  2722. xtooex  db '386Power: _OnExit list full, set an higher MAXX_EX',CR,LF,'$'
  2723.         align byte
  2724.         public _OnExit
  2725. _OnExit:
  2726.         ; add routine pointed by EAX to the exit-list
  2727.         ; (routines to call on exit)
  2728.         push ebx
  2729.         movzx ebx,excount
  2730.         cmp bl,MAXX_EX ; max. exit extensions allowed
  2731.         jnb tooex
  2732.         mov [ebx*4+ex_list],eax
  2733.         inc excount
  2734.         pop ebx
  2735.         ret
  2736. tooex:
  2737.         mov _386Return, offset xtooex
  2738.         ; .....continue into the exit routine
  2739.  
  2740. _Exit:  ; 32bit side of shutdown code
  2741.         cli
  2742.         cld
  2743.         ; set up a trusted register configuration
  2744.         mov ax,cs:_SelData
  2745.         mov ds,ax
  2746.         mov es,ax
  2747.         mov fs,ax
  2748.         mov ss,ax              ; termination, force stack
  2749.         mov esp,(STACKSIZE)*16 ; into a "safe" zone
  2750.         add esp,Stack32BaseOffset
  2751.         mov nextmodestack,(STACKSIZE-STACKUSER)*16 ;"reset" next stack frame
  2752.         mov gs,_SelZero
  2753.         ; execute custom shutdown code first
  2754.         movzx ebx,excount
  2755.         jmp short countcheck
  2756. exithem:
  2757.         dec ebx
  2758.         push ebx  ; save general register to avoid problems
  2759.         call [ebx*4+ex_list]
  2760.         cli
  2761.         pop ebx
  2762. countcheck:
  2763.         or ebx,ebx
  2764.         jne exithem
  2765.         ; now execute a generic exit
  2766.         mov ecx,_386Return  ;  Write exit message
  2767.         mov V86ah,9         ;
  2768.         add ecx,_Code32Base ;
  2769.         mov eax,ecx         ;
  2770.         shr ecx,4           ;
  2771.         and eax,0Fh         ;
  2772.         mov V86ds,cx        ;
  2773.         mov V86dx,ax        ;
  2774.         mov al,21h          ;
  2775.         call _ExecINT             ;
  2776.  
  2777.         mov eax,OldBreakISR              ; restore ctrl+break
  2778.         mov gs:[1bh*4],eax
  2779.  
  2780.         mov ax,OldIRQMask                ; restore PIC masks
  2781.         out 0a1h,al
  2782.         jc delay1  ; delay a little
  2783. delay1: jnc delay2 ;
  2784. delay2:            ;
  2785.         mov al,ah
  2786.         out 21h,al
  2787.  
  2788.         ; back to 16bit code16
  2789.         mov ds,_EXIT_DATA_SEL    ; this must be an alias (even a 16bit one)
  2790.                                  ; for code32
  2791.         jmp fword ptr _EXIT_ADDR
  2792.             
  2793. ;------------------------------------------------------------------------------
  2794. ; 32 bit DPMI system code
  2795. ;------------------------------------------------------------------------------
  2796. d32_ExecReal:        ; call real mode far proc: CX:DX=seg:off
  2797.         pushad
  2798.         pushfd
  2799.         shl ecx,16  ;  store seg:ofs into ECX
  2800.         mov cx,dx   ;
  2801.         
  2802.         mov ebp,offset callreal   ; redirect to CALL REAL MODE ROUTINE
  2803.         
  2804.         ; now join common int code
  2805.         jmp short d32_16common
  2806.         
  2807. d32_ExecINT: ; call real mode INT: AL=int num
  2808.         pushad
  2809.         pushfd
  2810.         ; AND HERE WE GO TO VIRTUAL 8086 MODE
  2811.         ; PUTTING INTO tempaddr the address of the interrupt vector to call
  2812.         ; from the _OldInt vector table
  2813.         and eax,0FFh
  2814.         mov ebp,offset intreal  ; redirect to INT REAL MODE ROUTINE
  2815.         mov ecx,[eax*4+_OldInt] ; get int handler into ecx
  2816.         ; join common int code
  2817.  
  2818. d32_16common:  ; int or call to real mode
  2819.         mov ax,0900h ; DPMI get state of Interrupt Flag and DISABLE IT
  2820.         int 31h
  2821.         ; AL = Interrupt Flag status
  2822.         push eax ; save Int Flag status
  2823.  
  2824.         mov tempaddr,ecx ; address to jump at in seg:ofs format
  2825.         
  2826.         push s32_SavStackOfs   ; save current SAVED stack
  2827.         push s32_SavStackSel   ;
  2828.         
  2829.         mov ebx,nextmodestack      ; allocate a new stack frame
  2830.  
  2831.         mov ax,ss ;
  2832.  
  2833.         sub nextmodestack,(STACKSWTR*16)      ; set new next stack
  2834.  
  2835.         mov es,ax ; ES == save state segment
  2836.         
  2837.         sub esp,d32_StateBufferSize ; allocate DPMI save state buffer
  2838.         mov edi,esp                 ;
  2839.         
  2840.         ; es:edi = pointer to save state buffer
  2841.         xor al,al                   ; AL=0 -> SAVE TASK STATE INFO
  2842.         call d32_SaveRestoreState   ; save DPMI info about this stack
  2843.         
  2844.         mov s32_SavStackOfs,esp  ; save stack
  2845.         mov s32_SavStackSel,ss   ;
  2846.         
  2847.         mov cx,V86es     ; real mode ES
  2848.         mov dx,codeend   ; real mode SS
  2849.         mov ax,code32    ; real mode DS
  2850.         
  2851.         mov edi,ebp     ; real mode EIP
  2852.         mov esi,code16   ; real mode CS
  2853.         jmp d32_Fast32_To_16
  2854.         
  2855.         ; DPMI RETURN FROM V86
  2856. d32_16done:
  2857.         mov edi,esp  ; current stack pos
  2858.         ; ES:EDI == pointer to save state buffer
  2859.         mov al,1                   ; AL=1 -> RESTORE TASK STATE INFO
  2860.         call d32_SaveRestoreState  ; get last DPMI info saved 
  2861.         
  2862.         add esp,d32_StateBufferSize ; remove DPMI INFO block
  2863.         
  2864.         pop s32_SavStackSel   ; Restore previous saved stack
  2865.         pop s32_SavStackOfs   ;
  2866.         
  2867.         add nextmodestack,STACKSWTR*16 ; restore space used for previous 
  2868.                                        ; stack frame
  2869.         
  2870.         pop eax    ; RESTORE Int Flag found on entry to mode-switch routine
  2871.         mov ah,9  ;
  2872.         int 31h   ; restore previous Int Flag status
  2873.         
  2874.         mov ax,ds        ; restore selectors
  2875.         mov es,ax        ;
  2876.         mov fs,ax        ;
  2877.         mov gs,_SelZero  ;
  2878.  
  2879.         popfd
  2880.         mov ah,byte ptr V86F
  2881.         sahf
  2882.         popad   ; restore registers
  2883.         ret
  2884.         
  2885. ;------------------------------------------------------------------------------        
  2886. ; DPMI IRQ redirectors (needed to make all IRQ vector selectors = CS)
  2887.          align dword
  2888. d32_irq0:        jmp fword ptr cs:d32_OldInts
  2889. d32_irq1:        jmp fword ptr cs:(8   + offset d32_OldInts)
  2890. d32_irq2:        jmp fword ptr cs:(16  + offset d32_OldInts)
  2891. d32_irq3:        jmp fword ptr cs:(24  + offset d32_OldInts)
  2892. d32_irq4:        jmp fword ptr cs:(32  + offset d32_OldInts)
  2893. d32_irq5:        jmp fword ptr cs:(40  + offset d32_OldInts)
  2894. d32_irq6:        jmp fword ptr cs:(48  + offset d32_OldInts)
  2895. d32_irq7:        jmp fword ptr cs:(56  + offset d32_OldInts)
  2896. d32_irq8:        jmp fword ptr cs:(64  + offset d32_OldInts)
  2897. d32_irq9:        jmp fword ptr cs:(72  + offset d32_OldInts)
  2898. d32_irqa:        jmp fword ptr cs:(80  + offset d32_OldInts)
  2899. d32_irqb:        jmp fword ptr cs:(88  + offset d32_OldInts)
  2900. d32_irqc:        jmp fword ptr cs:(96  + offset d32_OldInts)
  2901. d32_irqd:        jmp fword ptr cs:(104 + offset d32_OldInts)
  2902. d32_irqe:        jmp fword ptr cs:(112 + offset d32_OldInts)
  2903. d32_irqf:        jmp fword ptr cs:(120 + offset d32_OldInts)
  2904.  
  2905. ;------------------------------------------------------------------------------
  2906. ; DPMI IRQ REDIRECTORS
  2907. ;------------------------------------------------------------------------------
  2908.         align byte
  2909. ; DPMI get IRQ handler offset
  2910. ; In:
  2911. ;   BL - IRQ num (0-0fh)
  2912. ; Out:
  2913. ;   EDX - offset of IRQ handler
  2914.  
  2915. d32_getirq:
  2916.         push ebx
  2917.         push eax
  2918.         push ecx
  2919.         and ebx,0Fh
  2920.         mov eax,0204h ;upper word is resetted
  2921.         mov bl,[ebx+intslotnum]
  2922.         int 31h
  2923.         pop ecx
  2924.         pop eax
  2925.         pop ebx
  2926.         ret
  2927.  
  2928. ; DPMI set IRQ handler offset
  2929. ; In:
  2930. ;   BL - IRQ num (0-0fh)
  2931. ;   EDX - offset of IRQ handler
  2932.  
  2933. d32_setirq:
  2934.         pushad
  2935.         and ebx,0Fh
  2936.         mov cx,cs
  2937.         mov ax,0205h
  2938.         mov bl,[ebx+intslotnum]
  2939.         int 31h
  2940.         popad
  2941.         ret
  2942.         
  2943. ;---------------------------------------------------------------
  2944. ; SIMULATED INT 31h INTERRUPT FLAG FUNCTIONS UNDER VCPI,XMS,HARD
  2945. ;---------------------------------------------------------------
  2946.  
  2947. s32_int31: ; INT 31h: AX=900h,901h,902h
  2948.         cmp al,1
  2949.         mov al,[esp+9]
  2950.         jb short s32_int31f0
  2951.         ja short s32_int31f1
  2952.         or byte ptr [esp+9],2 ; set I.F.
  2953.         shr al,1  ;
  2954.         and al,1  ; return I.F. status BEFORE int call
  2955.         iretd
  2956. s32_int31f0:
  2957.         and byte ptr [esp+9],0fdh ; clear I.F.
  2958. s32_int31f1:
  2959.         shr al,1  ;
  2960.         and al,1  ; return I.F. status BEFORE int call
  2961.         iretd
  2962.  
  2963.  
  2964. ;-----------------------------------------------------------------------------
  2965. ; VCPI STUFF
  2966. ;-----------------------------------------------------------------------------
  2967.         
  2968. ; 386POWER API ints
  2969. v32_ExecReal:              ; real mode call far : CX:DX=seg:off
  2970.         pushad
  2971.         pushfd
  2972.         cli
  2973.         shl ecx,16
  2974.         mov cx,dx
  2975.         mov ebp,offset callreal
  2976.         jmp short v32_16common
  2977.         
  2978. v32_ExecINT:                 ; real mode INT : AL=int num
  2979.         pushad
  2980.         pushfd
  2981.         cli
  2982.         and eax,0FFh
  2983.         mov ebp,offset intreal
  2984.         mov ecx,[eax*4+_OldInt]
  2985.  
  2986. v32_16common: ; int or call to real mode
  2987.         mov esi,nextmodestack     ; new stack frame
  2988.         sub nextmodestack,(STACKSWTR*16)
  2989.         mov edi,code32
  2990.         mov tempaddr,ecx
  2991.         xor eax,eax
  2992.         push s32_SavStackOfs       ;
  2993.         mov s32_SavStackOfs,esp    ; save stack
  2994.         mov ebx,codeend ; SS value
  2995.         mov ax,V86es   ; ES value
  2996.         mov edx,code16
  2997.         push edi     ;  FS
  2998.         push edi     ;  GS
  2999.         push edi     ;  DS (will be switched to V86ds into real mode side)
  3000.         push eax     ;  ES
  3001.         push ebx     ;  SS
  3002.         push esi     ;  ESP
  3003.         sub esp,4   ; make space for eflags
  3004.         mov ebx,18h ; selzero
  3005.         mov eax,0de0ch  ; vcpi switch code
  3006.         push edx                ; CS
  3007.         push ebp                ; EIP = intreal xor callreal
  3008.         ; VCPI switch to real mode routine
  3009.         mov ds,bx
  3010.         call cs:v32_vcpientryaddr  ; n.b. this is a FAR call
  3011.         
  3012. v32_exec_d:  ; done with INT32/33 from V86 mode
  3013.         mov ebx,18h
  3014.         mov eax,10h
  3015.         mov gs,bx
  3016.         mov ds,ax
  3017.         mov es,ax
  3018.         mov fs,ax
  3019.         mov ss,ax
  3020.         mov esp,s32_SavStackOfs
  3021.         pop s32_SavStackOfs
  3022.         add nextmodestack,STACKSWTR*16
  3023.         popfd
  3024.         mov ah,byte ptr V86F
  3025.         sahf
  3026.         popad
  3027.         ret
  3028.         
  3029. ;------------------------------------------------------------------------        
  3030. ; exceptions handlers: some are terminal, others are redirected
  3031. ; to the irq handler.
  3032.         align byte
  3033. v32_exc: ; generic exception handler
  3034.         jmp _Exit ; TERMINATE PROGRAM (or at least try to)
  3035.  
  3036. ;-----------------------------------------------------------------------------
  3037. ; IRQ redirector between modes
  3038. ; this is the prot. mode to real mode switch-code
  3039.  
  3040.         align byte
  3041. v32_irq0:
  3042.         push ecx
  3043.         mov ecx,8
  3044.         jmp short v32_irq
  3045. v32_irq1:
  3046.         push ecx
  3047.         mov ecx,9
  3048.         jmp short v32_irq
  3049. v32_irq2:
  3050.         push ecx
  3051.         mov ecx,0ah
  3052.         jmp short v32_irq
  3053. v32_irq3:
  3054.         push ecx
  3055.         mov ecx,0bh
  3056.         jmp short v32_irq
  3057. v32_irq4:
  3058.         push ecx
  3059.         mov ecx,0ch
  3060.         jmp short v32_irq
  3061. v32_irq5:
  3062.         push ecx
  3063.         mov ecx,0dh
  3064.         jmp short v32_irq
  3065. v32_irq6:
  3066.         push ecx
  3067.         mov ecx,0eh
  3068.         jmp short v32_irq
  3069. v32_irq7:
  3070.         push ecx
  3071.         mov ecx,0fh
  3072.         jmp short v32_irq
  3073. v32_irq8:
  3074.         push ecx
  3075.         mov ecx,70h
  3076.         jmp short v32_irq
  3077. v32_irq9:
  3078.         push ecx
  3079.         mov ecx,71h
  3080.         jmp short v32_irq
  3081. v32_irqa:
  3082.         push ecx
  3083.         mov ecx,72h
  3084.         jmp short v32_irq
  3085. v32_irqb:
  3086.         push ecx
  3087.         mov ecx,73h
  3088.         jmp short v32_irq
  3089. v32_irqc:
  3090.         push ecx
  3091.         mov ecx,74h
  3092.         jmp short v32_irq
  3093. v32_irqd:
  3094.         push ecx
  3095.         mov ecx,75h
  3096.         jmp short v32_irq
  3097. v32_irqe:
  3098.         push ecx
  3099.         mov ecx,76h
  3100.         jmp short v32_irq
  3101. v32_irqf:
  3102.         push ecx
  3103.         mov ecx,77h
  3104. ;-----------------------------------------------------------------------------
  3105. ; generic IRQ handler, ecx =real mode INT to call
  3106. ;
  3107. v32_irq:
  3108.          
  3109.         push ds 
  3110.         push es 
  3111.         push fs 
  3112.         push gs
  3113.         pushad
  3114.         mov eax,10h ; _SelData
  3115.         mov ds,ax
  3116.         ; ecx has been already set with the int number to call
  3117.         mov ebp,[ecx*4+_OldInt]  ; set address of interrupt routine
  3118.  
  3119.         mov esi,nextmodestack                 ; new stack frame
  3120.         sub nextmodestack,(STACKSWTR*16)      ;
  3121.         mov eax,code32
  3122.         push s32_SavStackOfs       ; save stack
  3123.         mov s32_SavStackOfs,esp    ;
  3124.         push eax           ; GS
  3125.         push eax           ; FS
  3126.         mov  ebx,codeend
  3127.         push eax           ; DS
  3128.         push eax           ; ES
  3129.         push ebx           ; SS
  3130.         mov eax,code16
  3131.         push esi           ; ESP
  3132.         sub esp,4 ;make space for eflags
  3133.         mov edx,18h     ; set linear selector into edx
  3134.         push eax  ;cs
  3135.         db 68h                        ; 32bit PUSH IMMEDIATE offset v16_irqreal
  3136.         dd large offset v16_irqreal   ;
  3137.         ; VCPI switch to real mode routine
  3138.         mov eax,0de0ch
  3139.         mov ds,dx
  3140.         call cs:v32_vcpientryaddr  ; n.b. this is a FAR call
  3141.         
  3142. v32_irqret: ; now we are back from real mode handler
  3143.         mov eax,10h ; _SelData
  3144.         mov ds,ax
  3145.         mov ss,ax
  3146.         mov esp,s32_SavStackOfs   ; restore saved stack
  3147.         pop s32_SavStackOfs       ;
  3148.         
  3149.         add nextmodestack,STACKSWTR*16
  3150.         
  3151.         popad
  3152.         pop gs 
  3153.         pop fs 
  3154.         pop es 
  3155.         pop ds
  3156.         pop ecx
  3157.         iretd
  3158.  
  3159. ;------------------------------------------
  3160. ; vcpi irq from real mode to protected mode
  3161. ; "foot" into prot. mode
  3162. ;------------------------------------------
  3163.         align byte
  3164. v32_virqserver:
  3165.          ; IRQ reflection: real/v86 --> prot. mode
  3166.          ; this is an IRQ with a prot. mode handler
  3167.          ; happened while in real mode.
  3168.          ;
  3169.         mov eax,10h ; _SelData
  3170.         mov ds,ax
  3171.  
  3172.         mov ss,ax                             ;
  3173.         mov esp,nextmodestack                 ; reload stack pointer
  3174.         sub nextmodestack,(STACKSWTP*16)      ; adjust it to 32bit
  3175.         add esp,Stack32BaseOffset             ; and move "next stack" pointer
  3176.  
  3177.         ; ecx has been already set with the offset into the irq table
  3178.         ; of the handler to call
  3179.  
  3180.         pushfd                            ;
  3181.         call fword ptr [ecx+s32_irqtable] ; execute the p. mode irq
  3182.  
  3183.         
  3184.         mov  esi,s16_SavStackOfs ; get back real mode stack
  3185.  
  3186.         mov eax,code32
  3187.         mov  ebx,dword ptr s16_SavStackSeg
  3188.                         ;get back real mode segment (high word is zero)
  3189.         push eax           ; GS
  3190.         push eax           ; FS
  3191.         push eax           ; DS
  3192.         push eax           ; ES
  3193.         push ebx           ; SS
  3194.         push esi           ; ESP
  3195.         sub esp,4 ;make space for eflags
  3196.         mov edx,18h     ; set linear selector into edx
  3197.         db 68h      ; 32bit PUSH IMMEDIATE code16
  3198.         dd code16   ;
  3199.         db 68h                       ; 32bit PUSH IMMEDIATE offset v16_virqdone
  3200.         dd large offset v16_virqdone ;
  3201.         ; VCPI switch to real mode routine
  3202.         mov eax,0de0ch
  3203.         mov ds,dx
  3204.         call cs:v32_vcpientryaddr  ; n.b. this is a FAR call
  3205.  
  3206. ;-----------------------------------------------------------------------------
  3207. ; HARD/XMS STUFF
  3208. ;-----------------------------------------------------------------------------
  3209.                   
  3210. ; 386POWER API ints
  3211.         align byte
  3212. s32_ExecReal:                  ; real mode FAR proc: CX:DX=seg:off
  3213.         pushad
  3214.         pushfd
  3215.         cli
  3216.         shl ecx,16
  3217.         mov cx,dx
  3218.         mov edi,offset callreal
  3219.         jmp short s32_16common
  3220.         
  3221. s32_ExecINT:                   ; real mode INT: AL=int num
  3222.         pushad
  3223.         pushfd
  3224.         cli
  3225.         and eax,0FFh
  3226.         mov edi,offset intreal
  3227.         mov ecx,[eax*4+_OldInt]
  3228.  
  3229. s32_16common: ; int or call to real mode
  3230.         push s32_SavStackOfs       ;
  3231.         mov s32_SavStackOfs,esp    ; save stack
  3232.         mov esp,nextmodestack     ; new stack frame
  3233.         sub nextmodestack,(STACKSWTR*16)     ; ss:esp to new stack frame
  3234.         add esp,Stack32BaseOffset           ;
  3235.         ; (will be converted to 16bit by mode switch code)
  3236.         ; ECX = address/vector to call
  3237.         mov esi,code16    ; set "switcher" address
  3238.                           ; edi  already set to destination offset
  3239.         call fword ptr s32_switchentryaddr
  3240.  
  3241. s32_exec_d:  ; done with INT32/33 from V86 mode
  3242.         mov eax,10h               ; restore stack
  3243.         mov ss,ax                 ;
  3244.         mov esp,s32_SavStackOfs   ;
  3245.         pop s32_SavStackOfs       ;
  3246.  
  3247.         add nextmodestack,STACKSWTR*16
  3248.         popfd
  3249.         mov ah,byte ptr V86F
  3250.         sahf
  3251.         popad
  3252.         ret
  3253.         
  3254. ;------------------------------------------------------------------------        
  3255. ; exceptions handlers: some are terminal, others are redirected
  3256. ; to the irq handler.
  3257.         align byte
  3258. s32_exc: ; generic exception handler
  3259.         jmp _Exit ; TERMINATE PROGRAM (or at least try to)
  3260.  
  3261. ;-----------------------------------------------------------------------------
  3262. ; IRQ redirector between modes
  3263. ; this is the prot. mode to real mode switch-code
  3264.  
  3265.         align byte
  3266. s32_irq0:
  3267.         push ecx
  3268.         mov ecx,8
  3269.         jmp short s32_irq
  3270. s32_irq1:
  3271.         push ecx
  3272.         mov ecx,9
  3273.         jmp short s32_irq
  3274. s32_irq2:
  3275.         push ecx
  3276.         mov ecx,0ah
  3277.         jmp short s32_irq
  3278. s32_irq3:
  3279.         push ecx
  3280.         mov ecx,0bh
  3281.         jmp short s32_irq
  3282. s32_irq4:
  3283.         push ecx
  3284.         mov ecx,0ch
  3285.         jmp short s32_irq
  3286. s32_irq5:
  3287.         push ecx
  3288.         mov ecx,0dh
  3289.         jmp short s32_irq
  3290. s32_irq6:
  3291.         push ecx
  3292.         mov ecx,0eh
  3293.         jmp short s32_irq
  3294. s32_irq7:
  3295.         push ecx
  3296.         mov ecx,0fh
  3297.         jmp short s32_irq
  3298. s32_irq8:
  3299.         push ecx
  3300.         mov ecx,70h
  3301.         jmp short s32_irq
  3302. s32_irq9:
  3303.         push ecx
  3304.         mov ecx,71h
  3305.         jmp short s32_irq
  3306. s32_irqa:
  3307.         push ecx
  3308.         mov ecx,72h
  3309.         jmp short s32_irq
  3310. s32_irqb:
  3311.         push ecx
  3312.         mov ecx,73h
  3313.         jmp short s32_irq
  3314. s32_irqc:
  3315.         push ecx
  3316.         mov ecx,74h
  3317.         jmp short s32_irq
  3318. s32_irqd:
  3319.         push ecx
  3320.         mov ecx,75h
  3321.         jmp short s32_irq
  3322. s32_irqe:
  3323.         push ecx
  3324.         mov ecx,76h
  3325.         jmp short s32_irq
  3326. s32_irqf:
  3327.         push ecx
  3328.         mov ecx,77h
  3329. ;-----------------------------------------------------------------------------
  3330. ; generic IRQ handler, ecx =real mode INT to call
  3331. ;
  3332. s32_irq:
  3333.          ; reflect irq: prot. mode -> real mode
  3334.          ; this is an IRQ happened while in protected mode
  3335.          ; with a real mode interrupt handler, so we must switch back
  3336.          ; to real mode, execute the irq and then get back.
  3337.         push ds 
  3338.         push es 
  3339.         push fs 
  3340.         push gs     
  3341.         pushad
  3342.         mov eax,10h ; _SelData
  3343.         mov ebx,18h ; _SelZero
  3344.         mov ds,ax
  3345.         mov gs,bx
  3346.         
  3347.         push s32_SavStackOfs       ; save stack
  3348.         mov s32_SavStackOfs,esp    ;
  3349.         ; ecx has been already set with the int number to call
  3350.         mov ebp,[ecx*4+_OldInt]  ; set address of interrupt routine
  3351.  
  3352.         
  3353.         add esp,Stack32BaseOffset        ;
  3354.         mov esp,nextmodestack             ; new stack frame
  3355.         sub nextmodestack,(STACKSWTR*16)  ;
  3356.  
  3357.         mov esi,code16              ; set jump destination
  3358.         mov edi,offset s16_irqreal  ;
  3359.         db 0EAh                  ; jump to switchpoint
  3360.         dd large offset HARD_P2R ;
  3361.         dw 20h ; code16 selector ;
  3362.  
  3363. s32_irqret:
  3364.         mov esp,s32_SavStackOfs   ; restore saved stack
  3365.         pop s32_SavStackOfs       ;
  3366.         
  3367.         add nextmodestack,STACKSWTR*16
  3368.         
  3369.         popad
  3370.         pop gs 
  3371.         pop fs 
  3372.         pop es 
  3373.         pop ds
  3374.         pop ecx
  3375.         iretd
  3376.  
  3377. ;------------------------------------------
  3378. ; hard/xms irq from real mode to protected mode
  3379. ; "foot" into prot. mode
  3380. ;------------------------------------------
  3381.         align byte
  3382. s32_virqserver:
  3383.          ; irq reflection: real mode -> prot. mode
  3384.          ; this is an IRQ happened while in real mode
  3385.          ; with a prot. mode interrupt handler, so we must switch back
  3386.          ; to prot. mode, execute the irq and then get back.
  3387.  
  3388.          ; all segregs are properly set
  3389.          ; and stack is already converted to 32bit
  3390.  
  3391.          pushfd     ;
  3392.          call fword ptr [ecx+s32_irqtable] ; execute the p. mode irq
  3393.  
  3394.          mov esi,code16                    ; set return address
  3395.          mov edi,large offset s16_virqdone ;
  3396.          db 0EAh                  ; jump to switchpoint
  3397.          dd large offset HARD_P2R ;
  3398.          dw 20h ; code16 selector ;
  3399.  
  3400.  
  3401.  
  3402. ; Custom get IRQ handler offset
  3403. ; In:
  3404. ;   BL - IRQ num (0-0fh)
  3405. ; Out:
  3406. ;   EDX - offset of current IRQ handler
  3407. s32_getirq:
  3408.         push ebx
  3409.         pushfd
  3410.         cli
  3411.         and ebx,0Fh
  3412.  
  3413.         mov bl,[ebx+intslotnum] ; get int number
  3414.         mov edx, dword ptr [ebx*8+s32_irqtable]
  3415.                                          ; get offset from irqtable
  3416.                                          ; (uses less code)
  3417.         popfd
  3418.         pop ebx
  3419.         ret        
  3420.  
  3421.                   align word
  3422. v16_flexers       dw offset v16_virq0,offset v16_virq1,offset v16_virq2
  3423.                   dw offset v16_virq3,offset v16_virq4,offset v16_virq5
  3424.                   dw offset v16_virq6,offset v16_virq7,offset v16_virq8
  3425.                   dw offset v16_virq9,offset v16_virqa,offset v16_virqb
  3426.                   dw offset v16_virqc,offset v16_virqd,offset v16_virqe
  3427.                   dw offset v16_virqf
  3428. s16_flexers       dw offset s16_virq0,offset s16_virq1,offset s16_virq2
  3429.                   dw offset s16_virq3,offset s16_virq4,offset s16_virq5
  3430.                   dw offset s16_virq6,offset s16_virq7,offset s16_virq8
  3431.                   dw offset s16_virq9,offset s16_virqa,offset s16_virqb
  3432.                   dw offset s16_virqc,offset s16_virqd,offset s16_virqe
  3433.                   dw offset s16_virqf
  3434.  
  3435.                   align byte
  3436. ; Custom set IRQ handler offset
  3437. ; In:
  3438. ;   BL  - IRQ num (0-0fh)
  3439. ;   EDX - offset of new IRQ handler
  3440. s32_setirq:
  3441.         pushad
  3442.         pushfd
  3443.         cli
  3444.         push ebx
  3445.         push edx
  3446.  
  3447.         and ebx,0Fh  ; MASK to expand bl into ebx
  3448.  
  3449.         mov bl,[ebx+intslotnum] ; get irq int number into prot. mode IDT
  3450.  
  3451.         ; SET TABLE for reflection from real mode
  3452.         mov [ebx*8+s32_irqtable],edx
  3453.  
  3454.         ; SET PROT. MODE IDT ENTRY
  3455.         lea ecx,[ebx*8]      ; get location in IDT table
  3456.         add ecx,s32_idt32ptr ; get complete pointer to int entry
  3457.         mov [ecx],dx         ; modify descriptor for
  3458.         shr edx,16           ; new 32bit offset & same segment
  3459.         mov [ecx+6],dx       ;
  3460.  
  3461.         pop edx
  3462.         pop ebx
  3463.  
  3464.         ; now it's time to check for the reflection strategy
  3465.         ; between real and protected mode
  3466.  
  3467.         mov esi,offset s16_idt_default  ; XMS/HARD data
  3468.         mov edi,offset s16_flexers      ;
  3469.         cmp _386Man,IS_VCPI    ; if not vcpi, force irq reflection
  3470.         jne turn_on_reflector  ;
  3471.  
  3472.         ; if VCPI
  3473.         ;       irq reflection strategy is more complex
  3474.         ;       because vcpi does not fully support reflection
  3475.         ;       IRQ 0 and IRQ 1 cannot be directly reflected
  3476.         ;       because the VCPI server "interacts" with 'em
  3477.         ;       ( don't ask me why, maybe it's because the VCPI server
  3478.         ;         interacts with the keyboard controller, or maybe
  3479.         ;         it reflects itself 'em)
  3480.  
  3481.         ; first of all, check if we need to kill this
  3482.         mov esi,offset v16_idt_default
  3483.         mov edi,offset v16_flexers
  3484.         ; then check if this is an irq it is better to not reflect
  3485.         ; directly... (irq0 or irq1)
  3486.         or bl,bl
  3487.         je short s32_sirq_c4d
  3488.         cmp bl,1
  3489.         jne short turn_on_reflector
  3490. s32_sirq_c4d:
  3491.         cmp edx,[ebx*4+esi] ;Are we restoring the default handler ?
  3492.         je  short check4dos ;Yes! restore the real mode handler to default too!
  3493.         popfd
  3494.         popad
  3495.         ret
  3496.  
  3497. turn_on_reflector:
  3498.         ; this forces a full reflection from real to protected mode
  3499.         and ebx,0Fh                  ; set reflector's offset
  3500.         mov di,word ptr [ebx*2+edi]  ;
  3501. check4dos:               ;
  3502.         mov V86ds,code16 ; irq reflector's code segment
  3503.         cmp edx,[ebx*4+esi]     ; are we restoring the default handler ?
  3504.         jne  short map_real_int ; no, go set the reflector
  3505. control_to_dos: ; yes, restore "real" real mode handler
  3506.         mov eax,[ebx*4+_OldInt]
  3507.         mov edi,eax  ; copy seg:offset and avoid to use the "word" override
  3508.         shr eax,16
  3509.         mov V86ds,ax ; irq reflector's code segment
  3510. map_real_int:
  3511.         mov ax,02508h  ; set interrupt vectors MS-DOS function
  3512.                        ; irq 0 ...  7  (master pic irqs) starts from int 8
  3513.         cmp bl,8
  3514.         jb enslave
  3515.         mov al,(70h-8) ; irq 8 ... 15 (slave pic irqs) starts from int 70h
  3516. enslave:
  3517.         mov V86dx,di
  3518.         add al,bl
  3519.         mov V86ax,ax
  3520.         mov al,21h
  3521.         call _ExecINT
  3522.         ; IRQ installation and reflection completed
  3523.         popfd
  3524.         popad
  3525.         ret
  3526.  
  3527.  
  3528.         
  3529. ; physical memory mapper
  3530.         align dword
  3531. _MapMemBase   dd 0
  3532. _MapMemTop    dd 0
  3533. _PhysMapTable dd 0  ; page table ptr initialized by startup code
  3534.         align byte
  3535.  
  3536. map_soo_hard:
  3537.         ; well, this is a simple conversion from "linear"
  3538.         ; to code32 (no paging under XMS and HARD mode)
  3539.         sub eax,_Code32Base
  3540.         clc
  3541.         ret
  3542.  
  3543.         public _MapPhysMem
  3544. _MapPhysMem:
  3545.         ; in:
  3546.         ; eax = phys mem base , edx = phys mem size
  3547.         ; out:
  3548.         ; IF CARRY CLEAR eax = code32 offset equivalent to base address
  3549.         ; ELSE ERROR
  3550.         cmp _386Man,IS_DPMI
  3551.         je dpmimap
  3552.         cmp _386Man,IS_VCPI
  3553.         jne map_soo_hard
  3554. vcpimap:push edx
  3555.         push ebx
  3556.         push ecx
  3557.         push edi
  3558.         mov ebx,_MapMemBase
  3559.         add edx,4095
  3560.         mov ecx,_MapMemTop
  3561.         and edx,0FFFFF000h ; round to pages
  3562.         sub ecx,ebx ; available space
  3563.         cmp ecx,edx
  3564.         jb nophyspace
  3565.         mov ecx,edx
  3566.         shr edx,12 ; get how many pages to allocate        
  3567.         add ecx,ebx 
  3568.         mov _MapMemBase,ecx ; set new base
  3569.         ; ebx = value to return
  3570.         and eax,0FFFFF000h ; page align and set paging bits
  3571.         or al,7        ;
  3572.         mov edi,_PhysMapTable
  3573. pluppa:        
  3574.         mov [edi],eax
  3575.         add eax,1000h
  3576.         dec edx
  3577.         jne pluppa
  3578.         mov _PhysMapTable,edi
  3579.         mov eax,ebx ; base offset
  3580.         clc
  3581. gpout:        
  3582.         pop edi
  3583.         pop ecx
  3584.         pop ebx
  3585.         pop edx
  3586.         ret
  3587. nophyspace:
  3588.         stc
  3589.         jmp short gpout        
  3590.         
  3591. dpmimap:        
  3592.         pushad
  3593.         mov _MapMemBase,0
  3594.         mov cx,ax
  3595.         shr eax,16        
  3596.         mov di,dx
  3597.         mov bx,ax
  3598.         shr edx,16        
  3599.         mov si,dx
  3600.         mov ax,800h
  3601.         int 31h
  3602.         jc soo_bad
  3603.         mov ax,bx
  3604.         shl eax,16
  3605.         mov ax,cx
  3606.         mov _MapMemBase,eax
  3607.         popad
  3608.         mov eax,_MapMemBase
  3609.         clc
  3610.         ret
  3611. soo_bad:stc
  3612.         popad
  3613.         ret
  3614.  
  3615.         align byte
  3616. v32_retreal: ; VCPI return to real mode ( called from _Exit routine)
  3617.         mov ebx,((STACKSIZE-(STACKUSER/2))*16)
  3618.         mov edx,code32
  3619.         mov ecx,codeend
  3620.         mov esi,code16
  3621.         mov edi, offset v16_retreal
  3622.         ; now set-up the return environment
  3623.         ; (n.b. 16bit values MUST be pushed as dwords)
  3624.         push edx   ; DWORD  GS  = code32
  3625.         push edx   ; DWORD  FS  = code32
  3626.         push edx   ; DWORD  DS  = code32
  3627.         push edx   ; DWORD  ES  = code32
  3628.         push ecx   ; DWORD  SS  = codeend
  3629.         push ebx   ; DWORD ESP  = translated SP
  3630.         sub esp,4  ; make space for eflags
  3631.         push esi   ; DWORD  CS  = code16
  3632.         mov ax,18h
  3633.         push edi   ; DWORD EIP  = offset v16_retreal
  3634.         mov ds,ax ; load linear memory descriptor into DS
  3635.         mov ax,0de0ch
  3636.         call cs:v32_vcpientryaddr ; N.B. this is a FAR call with no return
  3637.  
  3638. ; Virtual DMA support module (integrated into the dos-extender)
  3639. ; It uses the Virtual DMA services and directly access the DMA hardware
  3640. ; to provide an higher level interface to VDS scatter/gather DMA
  3641. ; As you can see the VDS is called from VIRTUAL 8086 MODE
  3642. ; the main reason for this is that i'm not sure if ALL the current VDS 
  3643. ; implementations let you use VDS from protected mode
  3644. ; (if you know more, please tell me)
  3645.  
  3646. _VDSVersion   dw 0 ; version
  3647. _VDSPNumber   dw 0 ; Product number
  3648. _VDSPRevision dw 0 ; product revision
  3649. _VDSFlags     dw 0 ; Virtual DMA Services flags
  3650.                    ; (see the VDS doc on x2ftp.oulu.fi for more info)
  3651.             public _VDSVersion,_VDSPNumber,_VDSPRevision,_VDSFlags
  3652.  
  3653. DMAPAGE db 87h,83h,81h,82h,8Fh,8Bh,89h,8Ah
  3654.  
  3655.  
  3656.  
  3657. ;Initializes the VDMA system
  3658. VDMAInit: ; out: Carry clear if OK
  3659.           ;      eax=number of dma channels
  3660.         ; current initialization stuff does nothing
  3661.         mov eax,16
  3662.         clc ; initialized
  3663.         ret
  3664.         
  3665. VDMACheck: ; out: carry clear if OK
  3666.         ; checks for VDMA support installed
  3667.         ; (always present under VCPI and DPMI)
  3668.         ; (never present under XMS and "raw 386", direct access to services is
  3669.         ;  used instead)
  3670.         clc ; present
  3671.         ret
  3672.  
  3673. ; ScatterList structure (returned by a call to _DMAMap )
  3674. VDMA_PTR   = 0  ; dd code32 relative pointer
  3675. VDMA_SIZE  = 4  ; dd size
  3676. VDMA_OFS   = 8  ; dd offset (the current version uses low memory)
  3677. VDMA_SEG   = 12 ; dw real mode offset (the current version uses low mem)
  3678. VDMA_PAGES = 16 ; pages requested
  3679. VDMA_USED  = 18 ; pages actually allocated  (use this to determine
  3680.                 ; how many (code32,physical) address couples
  3681.                 ; are present starting from VDMA_SCATS
  3682. VDMA_SCATS = 20 ; start of "couples" of scattered page entries
  3683. ; where the VDS server puts only page entries
  3684. ; the VDMA system will put COUPLES of dwords
  3685. ; (the first dword is the code32 relative
  3686. ; offset of the page,the 2nd dword is the physical address you have to send
  3687. ; to the dma hardware
  3688. ; so at offset VDMA_SCATS    you find the code32 address of the first page
  3689. ;          at  VDMA_SCATS+4  you find the equivalent PHYSICAL address
  3690. ; and so on ...
  3691.  
  3692. ; Allocates & initializes a VDMA ScatterList into low memory
  3693. ; IN: EAX= Size of buffer
  3694. ; OUT: if Carry Clear then
  3695. ;         EAX = Ptr to Scatterlist, _LoMemBase Updated
  3696. ;      else EAX= pointer to error string for 386Return
  3697. DScatLock:
  3698.         push ecx
  3699.         push edx
  3700.         push ebx
  3701.         push esi
  3702.         push edi
  3703.         add eax,000000FFFh ; align size to page boundary
  3704.         mov ebx,eax
  3705.         mov esi,_LoMemBase
  3706.         and eax,0FFFFF000h ; align address to page
  3707.         shr ebx,12 ; how many pages ?
  3708.         lea ecx,[eax+ebx*8+(20+0FFFh)] ; worst case allocation
  3709.                 ; eax= size requested (aligned to 4k page)
  3710.                 ; ebx= size of scatter/gather list
  3711.                 ; plus "overflow" constants
  3712.         mov edx,_LoMemTop
  3713.         sub edx,esi
  3714.         sub edx,ecx
  3715.         jb FAILURE
  3716.         sub edx,(LOWMIN*1024)
  3717.         jb FAILURE
  3718.         add esi,ecx
  3719.         mov _LoMemBase,esi ; Store NEW low memory base
  3720.         sub esi,ecx
  3721.         add esi,_Code32Base ; get linear address
  3722.         lea edi,[esi+ebx*8+20] ;LINEAR start of dma data region
  3723.         mov [esi+VDMA_SIZE],eax ; SET SIZE
  3724.         add edi,000000FFFh ; align to page boundary
  3725.         and edi,0FFFFF000h ;
  3726.         mov [esi+VDMA_PAGES],ebx ; SET AVAILABLE PAGES (and zeroes VDMA_USED)
  3727.         mov [esi],edi  ; SET ALIGNED ADDRESS
  3728.         mov  ecx,edi
  3729.         mov  edx,edi
  3730.         and  ecx,0Fh ; ofs
  3731.         shr  edx,4   ; seg
  3732.         mov [esi+VDMA_OFS],ecx ; SET REAL MODE OFS
  3733.         mov [esi+VDMA_SEG],edx ; SET REAL MODE SEG
  3734.         cmp _386Man,IS_XMS
  3735.         je falselock
  3736.         cmp _386Man,IS_HARD
  3737.         je falselock
  3738.         pushad
  3739.         add esi,4
  3740.         mov ecx,esi
  3741.         mov edx,esi
  3742.         and ecx,0Fh
  3743.         shr edx,4
  3744.         mov V86ax,8105h ; Lock
  3745.         mov al,4Bh
  3746.         mov V86di,cx
  3747.         mov V86es,dx
  3748.         mov V86dx,0040h ;4k scatter/gather
  3749.         call _ExecINT
  3750.         popad
  3751.         jc FAILURE
  3752. falsedone:
  3753.         ; Well! Now expand the scatter/gather structure with
  3754.         ; the code32 relative values
  3755.         push esi ; save pointer to table
  3756.         lea edx,[edi+eax-4096] ; code32 offset of last page
  3757.         lea esi,[edi+ebx*4-4]  ; last page entry
  3758.         lea edi,[edi+ebx*8-8]  ; last extended page entry
  3759. extrloader:        
  3760.         mov eax,[esi]
  3761.         mov [edi],edx
  3762.         sub esi,4
  3763.         mov [edi+4],eax
  3764.         sub edx,4096
  3765.         sub edi,8
  3766.         dec ebx
  3767.         jne extrloader
  3768.         pop eax ;get back pointer to scatter/gather table
  3769.         ; here carry is clear
  3770. FAILURE:        
  3771.         pop edi
  3772.         pop esi
  3773.         pop ebx
  3774.         pop edx 
  3775.         pop ecx
  3776.         ret
  3777.  
  3778. falselock:
  3779.         ; edi =linear start of region to lock
  3780.         ; esi =scatter list
  3781.         ; ebx =pages to allocate
  3782.         pushad
  3783. scatset:
  3784.         mov [esi+VDMA_SCATS],edi
  3785.         add esi,4
  3786.         add edi,4096
  3787.         dec ebx
  3788.         jne scatset
  3789.         popad
  3790.         jmp short falsedone
  3791.                      
  3792. ; Frees a VDMA ScatterList
  3793. ; IN: EAX= ScatterList to unlock
  3794.  
  3795. falseunlock:
  3796.         clc
  3797.         ret
  3798.  
  3799. DScatUnLock:
  3800.         pushad
  3801.         cmp _386Man,IS_XMS
  3802.         je falseunlock
  3803.         cmp _386Man,IS_HARD
  3804.         je falseunlock
  3805.         xor ebx,ebx
  3806.         lea ecx,[eax+4]
  3807.         lea edi,[eax+(4+VDMA_SCATS)] 
  3808.         mov  bx,[eax+VDMA_PAGES]     
  3809.         lea esi,[eax+VDMA_SCATS]     
  3810.         mov edx,ecx
  3811. GatherPack:
  3812.         mov eax,[esi]
  3813.         mov [edi],eax
  3814.         add esi,4
  3815.         add edi,8
  3816.         dec ebx
  3817.         jne GatherPack
  3818.         ;
  3819.         and ecx,0Fh
  3820.         shr edx,4
  3821.         mov V86ax,8106h ; Unlock
  3822.         mov al,4Bh
  3823.         mov V86di,cx
  3824.         mov V86es,dx
  3825.         mov V86dx,0040h ;4k scatter/gather
  3826.         call _ExecINT
  3827.         popad
  3828.         ret
  3829.  
  3830.  
  3831. ; Locks a DMA channel, EAX = channel number 
  3832. ; Carry set if error
  3833. DChanLock:
  3834.         cmp _386Man,IS_XMS
  3835.         je  lok
  3836.         cmp _386Man,IS_HARD
  3837.         je lok
  3838.         mov V86ax,0810Bh
  3839.         mov V86bx,ax
  3840.         mov V86dx,0000h
  3841.         mov al,4bh
  3842.         call _ExecINT
  3843.         ret
  3844. lok:
  3845.         clc
  3846.         ret
  3847.  
  3848. ; Unlocks a DMA channel, EAX = channel number 
  3849. ; Carry set if error
  3850. DChanUnLock:
  3851.         cmp _386Man,IS_XMS
  3852.         je  lok
  3853.         cmp _386Man,IS_HARD
  3854.         je lok
  3855.         mov V86ax,0810Ch
  3856.         mov V86bx,ax
  3857.         mov V86dx,0000h
  3858.         mov al,4bh
  3859.         call _ExecINT
  3860.         ret
  3861.  
  3862. ; Sends data TO a device using DMA
  3863. ; EAX = channel, EBX = Physical mem ptr, ECX = Lenght in BYTES
  3864. ; n.b.if you send/receive on a 16bit channel (4..7) remember to keep
  3865. ;     address and byte count WORD ALIGNED
  3866. ; Remember that using the scatterlist you have to send data in chunks
  3867. ; of up to 4k bytes (not a big problem to me, if you use dma to send
  3868. ; voice data you HAVE to scatter it to perform software mixing)
  3869.  
  3870. VDMASend:
  3871.         pushad
  3872.         test al,4 ; using 16 bit channels ?
  3873.         jnz DMA16
  3874. DMA8:   mov ah,al
  3875.  
  3876.         or al,4 ; set mask to disable dma
  3877.         out 0Ah,al ; mask reg
  3878.         
  3879.         xor al,al
  3880.         out 0Ch,al ; clear byte ptr
  3881.  
  3882.         mov al,48h ; write to device       
  3883.         or  al,ah 
  3884.         out 0Bh,al ; mode
  3885.         
  3886.         xor edx,edx
  3887.         mov al,bl
  3888.         add dl,ah  ; dx = dma address
  3889.         out dx,al  ; address LSB
  3890.         mov al,bh
  3891.         out dx,al  ; address MSB
  3892.         
  3893.         inc edx    ;dx = dma counter
  3894.         
  3895.         shr ebx,16 ; get page number into bl
  3896.         
  3897.         mov al,cl
  3898.         out dx,al  ; counter LSB
  3899.         mov al,ch
  3900.         out dx,al  ; counter MSB
  3901.         
  3902.         mov dl,ah
  3903.         mov al,bl
  3904.         mov dl,[edx+DMAPAGE]
  3905.         out dx,al             ; send page
  3906.         
  3907.         mov al,ah  ; UNmask DMA channel
  3908.         out 0Ah,al ; 
  3909.         popad
  3910.         ret
  3911. DMA16:  mov ah,al
  3912.         xor edx,edx ;@ INTER...
  3913.         out 0D4h,al ; mask reg (mask already se because of channel number)
  3914.         and ah,3    ; clear higher bit to get chip dma number
  3915.         shr ebx,1 ; WORD ALIGN 16BIT DMA ADDR
  3916.         xor al,al
  3917.         out 0D8h,al ; clear byte ptr
  3918.         mov dl,ah   ;@...LEAVE  ....
  3919.         mov al,48h ; write to device       
  3920.         or  al,ah 
  3921.         shl edx,1   ;@... THIS ....
  3922.         out 0D6h,al ; mode
  3923.         shr ecx,1  ;WORD ALIGN 16BIT DMA COUNTER
  3924.         mov al,bl
  3925.         add dl,0C0h  ; dx = dma address ...STUFF TO GET THE CORRECT ADDR
  3926.         out dx,al    ; address LSB
  3927.         mov al,bh
  3928.         out dx,al  ; address MSB
  3929.         
  3930.         add  edx,2 ;dx = dma counter
  3931.         
  3932.         shr ebx,16 ; get page number into bl cutting out bit 17
  3933.         
  3934.         mov al,cl
  3935.         out dx,al  ; counter LSB
  3936.         shl ebx,1  ; PAGE ALIGN INTO STANDARD FORMAT
  3937.         mov al,ch
  3938.         out dx,al  ; counter MSB
  3939.         
  3940.         mov dl,ah
  3941.         mov al,bl
  3942.         mov dl,[edx+DMAPAGE]
  3943.         out dx,al             ; send page
  3944.         
  3945.         mov al,ah   ; UNmask DMA channel
  3946.         out 0D4h,al ; 
  3947.         popad
  3948.         ret
  3949.  
  3950. ; receives data FROM a device using DMA
  3951. ; EAX = channel, EBX = Physical mem ptr, ECX = Lenght in BYTES
  3952. ; n.b.if you send/receive on a 16bit channel (4..7) remember to keep
  3953. ;     address and byte count WORD ALIGNED
  3954. ; Remember that using the scatterlist you have to send data in chunks
  3955. ; of up to 4k bytes (not a big problem to me, if you use dma to send
  3956. ; voice data you HAVE to scatter it to perform software mixing)
  3957.  
  3958. VDMAReceive:
  3959.         pushad
  3960.         test al,4 ; using 16 bit channels ?
  3961.         jnz RDMA16
  3962. RDMA8:   mov ah,al
  3963.  
  3964.         or al,4 ; set mask to disable dma
  3965.         out 0Ah,al ; mask reg
  3966.         
  3967.         xor al,al
  3968.         out 0Ch,al ; clear byte ptr
  3969.  
  3970.         mov al,44h ; read from device
  3971.         or  al,ah 
  3972.         out 0Bh,al ; mode
  3973.         
  3974.         xor edx,edx
  3975.         mov al,bl
  3976.         add dl,ah  ; dx = dma address
  3977.         out dx,al  ; address LSB
  3978.         mov al,bh
  3979.         out dx,al  ; address MSB
  3980.         
  3981.         inc edx    ;dx = dma counter
  3982.         
  3983.         shr ebx,16 ; get page number into bl
  3984.         
  3985.         mov al,cl
  3986.         out dx,al  ; counter LSB
  3987.         mov al,ch
  3988.         out dx,al  ; counter MSB
  3989.         
  3990.         mov dl,ah
  3991.         mov al,bl
  3992.         mov dl,[edx+DMAPAGE]
  3993.         out dx,al             ; send page
  3994.         
  3995.         mov al,ah  ; UNmask DMA channel
  3996.         out 0Ah,al ; 
  3997.         popad
  3998.         ret
  3999. RDMA16:  mov ah,al
  4000.         xor edx,edx ;@ INTER...
  4001.         out 0D4h,al ; mask reg (mask already se because of channel number)
  4002.         and ah,3    ; clear higher bit to get chip dma number
  4003.         shr ebx,1 ; WORD ALIGN 16BIT DMA ADDR
  4004.         xor al,al
  4005.         out 0D8h,al ; clear byte ptr
  4006.         mov dl,ah   ;@...LEAVE  ....
  4007.         mov al,44h ; read from device
  4008.         or  al,ah 
  4009.         shl edx,1   ;@... THIS ....
  4010.         out 0D6h,al ; mode
  4011.         shr ecx,1  ;WORD ALIGN 16BIT DMA COUNTER
  4012.         mov al,bl
  4013.         add dl,0C0h  ; dx = dma address ...STUFF TO GET THE CORRECT ADDR
  4014.         out dx,al    ; address LSB
  4015.         mov al,bh
  4016.         out dx,al  ; address MSB
  4017.         
  4018.         add  edx,2 ;dx = dma counter
  4019.         
  4020.         shr ebx,16 ; get page number into bl cutting out bit 17
  4021.         
  4022.         mov al,cl
  4023.         out dx,al  ; counter LSB
  4024.         shl ebx,1  ; PAGE ALIGN INTO STANDARD FORMAT
  4025.         mov al,ch
  4026.         out dx,al  ; counter MSB
  4027.         
  4028.         mov dl,ah
  4029.         mov al,bl
  4030.         mov dl,[edx+DMAPAGE]
  4031.         out dx,al             ; send page
  4032.         
  4033.         mov al,ah   ; UNmask DMA channel
  4034.         out 0D4h,al ; 
  4035.         popad
  4036.         ret
  4037.  
  4038. code32  ends
  4039.  
  4040. ; End of program 
  4041. ; (codeend segment must be at end of program or you will get lots of pain)
  4042.  
  4043. codeend segment page stack use32 'stack'
  4044. db      STACKSIZE*16 dup(?)
  4045.         ; Stack Starts here
  4046. codeend ends
  4047.         ; Boot16 is program starting point
  4048.         end     Boot16
  4049.  
  4050.